diff options
Diffstat (limited to 'app/graphql')
96 files changed, 642 insertions, 239 deletions
diff --git a/app/graphql/graphql_triggers.rb b/app/graphql/graphql_triggers.rb index 290cd4d7146..ac1a4a6b9ef 100644 --- a/app/graphql/graphql_triggers.rb +++ b/app/graphql/graphql_triggers.rb @@ -8,4 +8,8 @@ module GraphqlTriggers def self.issue_crm_contacts_updated(issue) GitlabSchema.subscriptions.trigger('issueCrmContactsUpdated', { issuable_id: issue.to_gid }, issue) end + + def self.issuable_title_updated(issuable) + GitlabSchema.subscriptions.trigger('issuableTitleUpdated', { issuable_id: issuable.to_gid }, issuable) + end end diff --git a/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb b/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb index c4f91d0c15c..b1db355aa40 100644 --- a/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb +++ b/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb @@ -8,7 +8,7 @@ module Mutations ADMIN_MESSAGE = 'You must be an admin to use this mutation' - ::Gitlab::ApplicationContext::KNOWN_KEYS.each do |key| + ::Gitlab::ApplicationContext.known_keys.each do |key| argument key, GraphQL::Types::String, required: false, diff --git a/app/graphql/mutations/alert_management/http_integration/create.rb b/app/graphql/mutations/alert_management/http_integration/create.rb index 04840ac43bd..f8d1a383706 100644 --- a/app/graphql/mutations/alert_management/http_integration/create.rb +++ b/app/graphql/mutations/alert_management/http_integration/create.rb @@ -4,10 +4,10 @@ module Mutations module AlertManagement module HttpIntegration class Create < HttpIntegrationBase - include FindsProject - graphql_name 'HttpIntegrationCreate' + include FindsProject + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project to create the integration in.' diff --git a/app/graphql/mutations/alert_management/prometheus_integration/create.rb b/app/graphql/mutations/alert_management/prometheus_integration/create.rb index 0153bd0e42a..9c3aefce033 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/create.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/create.rb @@ -4,10 +4,10 @@ module Mutations module AlertManagement module PrometheusIntegration class Create < PrometheusIntegrationBase - include FindsProject - graphql_name 'PrometheusIntegrationCreate' + include FindsProject + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project to create the integration in.' diff --git a/app/graphql/mutations/boards/create.rb b/app/graphql/mutations/boards/create.rb index 080bf7c6e79..773ba08a291 100644 --- a/app/graphql/mutations/boards/create.rb +++ b/app/graphql/mutations/boards/create.rb @@ -3,10 +3,9 @@ module Mutations module Boards class Create < ::Mutations::BaseMutation - include Mutations::ResolvesResourceParent - graphql_name 'CreateBoard' + include Mutations::ResolvesResourceParent include Mutations::Boards::CommonMutationArguments field :board, diff --git a/app/graphql/mutations/branches/create.rb b/app/graphql/mutations/branches/create.rb index 078c84bcdc0..b851622bfde 100644 --- a/app/graphql/mutations/branches/create.rb +++ b/app/graphql/mutations/branches/create.rb @@ -3,10 +3,10 @@ module Mutations module Branches class Create < BaseMutation - include FindsProject - graphql_name 'CreateBranch' + include FindsProject + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the branch is associated with.' diff --git a/app/graphql/mutations/ci/ci_cd_settings_update.rb b/app/graphql/mutations/ci/ci_cd_settings_update.rb index 7bd38bc2998..dec90ced962 100644 --- a/app/graphql/mutations/ci/ci_cd_settings_update.rb +++ b/app/graphql/mutations/ci/ci_cd_settings_update.rb @@ -3,10 +3,10 @@ module Mutations module Ci class CiCdSettingsUpdate < BaseMutation - include FindsProject - graphql_name 'CiCdSettingsUpdate' + include FindsProject + authorize :admin_project argument :full_path, GraphQL::Types::ID, diff --git a/app/graphql/mutations/ci/job_token_scope/add_project.rb b/app/graphql/mutations/ci/job_token_scope/add_project.rb index 41adcae2c82..e16c08cb116 100644 --- a/app/graphql/mutations/ci/job_token_scope/add_project.rb +++ b/app/graphql/mutations/ci/job_token_scope/add_project.rb @@ -4,10 +4,10 @@ module Mutations module Ci module JobTokenScope class AddProject < BaseMutation - include FindsProject - graphql_name 'CiJobTokenScopeAddProject' + include FindsProject + authorize :admin_project argument :project_path, GraphQL::Types::ID, diff --git a/app/graphql/mutations/ci/job_token_scope/remove_project.rb b/app/graphql/mutations/ci/job_token_scope/remove_project.rb index dd6b2358dd5..f503b4f2f7a 100644 --- a/app/graphql/mutations/ci/job_token_scope/remove_project.rb +++ b/app/graphql/mutations/ci/job_token_scope/remove_project.rb @@ -4,10 +4,10 @@ module Mutations module Ci module JobTokenScope class RemoveProject < BaseMutation - include FindsProject - graphql_name 'CiJobTokenScopeRemoveProject' + include FindsProject + authorize :admin_project argument :project_path, GraphQL::Types::ID, diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb index 88dc426398b..21c3d55881c 100644 --- a/app/graphql/mutations/ci/runner/delete.rb +++ b/app/graphql/mutations/ci/runner/delete.rb @@ -20,7 +20,7 @@ module Mutations error = authenticate_delete_runner!(runner) return { errors: [error] } if error - runner.destroy! + ::Ci::UnregisterRunnerService.new(runner).execute { errors: runner.errors.full_messages } end diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb index e37ab1081f9..e6123b4283a 100644 --- a/app/graphql/mutations/ci/runner/update.rb +++ b/app/graphql/mutations/ci/runner/update.rb @@ -28,7 +28,12 @@ module Mutations argument :active, GraphQL::Types::Boolean, required: false, - description: 'Indicates the runner is allowed to receive jobs.' + description: 'Indicates the runner is allowed to receive jobs.', + deprecated: { reason: :renamed, replacement: 'paused', milestone: '14.8' } + + argument :paused, GraphQL::Types::Boolean, + required: false, + description: 'Indicates the runner is not allowed to receive jobs.' argument :locked, GraphQL::Types::Boolean, required: false, description: 'Indicates the runner is locked.' diff --git a/app/graphql/mutations/clusters/agents/create.rb b/app/graphql/mutations/clusters/agents/create.rb index 0896cc7b203..deaa9c2d656 100644 --- a/app/graphql/mutations/clusters/agents/create.rb +++ b/app/graphql/mutations/clusters/agents/create.rb @@ -4,12 +4,12 @@ module Mutations module Clusters module Agents class Create < BaseMutation + graphql_name 'CreateClusterAgent' + include FindsProject authorize :create_cluster - graphql_name 'CreateClusterAgent' - argument :project_path, GraphQL::Types::ID, required: true, description: 'Full path of the associated project for this cluster agent.' diff --git a/app/graphql/mutations/commits/create.rb b/app/graphql/mutations/commits/create.rb index 3eb1912dbc4..00ec64becc8 100644 --- a/app/graphql/mutations/commits/create.rb +++ b/app/graphql/mutations/commits/create.rb @@ -3,6 +3,8 @@ module Mutations module Commits class Create < BaseMutation + graphql_name 'CommitCreate' + include FindsProject class UrlHelpers @@ -10,8 +12,6 @@ module Mutations include Gitlab::Routing end - graphql_name 'CommitCreate' - argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the branch is associated with.' diff --git a/app/graphql/mutations/concerns/mutations/can_mutate_spammable.rb b/app/graphql/mutations/concerns/mutations/can_mutate_spammable.rb deleted file mode 100644 index f1ae54aa014..00000000000 --- a/app/graphql/mutations/concerns/mutations/can_mutate_spammable.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -module Mutations - # This concern is deprecated and will be deleted in 14.6 - # - # Use the SpamProtection concern instead. - module CanMutateSpammable - extend ActiveSupport::Concern - - DEPRECATION_NOTICE = { - reason: 'Use spam protection with HTTP headers instead', - milestone: '13.11' - }.freeze - - included do - argument :captcha_response, GraphQL::Types::String, - required: false, - deprecated: DEPRECATION_NOTICE, - description: 'Valid CAPTCHA response value obtained by using the provided captchaSiteKey with a CAPTCHA API to present a challenge to be solved on the client. Required to resubmit if the previous operation returned "NeedsCaptchaResponse: true".' - - argument :spam_log_id, GraphQL::Types::Int, - required: false, - deprecated: DEPRECATION_NOTICE, - description: 'Spam log ID which must be passed along with a valid CAPTCHA response for the operation to be completed. Required to resubmit if the previous operation returned "NeedsCaptchaResponse: true".' - - field :spam, - GraphQL::Types::Boolean, - null: true, - deprecated: DEPRECATION_NOTICE, - description: 'Indicates whether the operation was detected as definite spam. There is no option to resubmit the request with a CAPTCHA response.' - - field :needs_captcha_response, - GraphQL::Types::Boolean, - null: true, - deprecated: DEPRECATION_NOTICE, - description: 'Indicates whether the operation was detected as possible spam and not completed. If CAPTCHA is enabled, the request must be resubmitted with a valid CAPTCHA response and spam_log_id included for the operation to be completed. Included only when an operation was not completed because "NeedsCaptchaResponse" is true.' - - field :spam_log_id, - GraphQL::Types::Int, - null: true, - deprecated: DEPRECATION_NOTICE, - description: 'Spam log ID which must be passed along with a valid CAPTCHA response for an operation to be completed. Included only when an operation was not completed because "NeedsCaptchaResponse" is true.' - - field :captcha_site_key, - GraphQL::Types::String, - null: true, - deprecated: DEPRECATION_NOTICE, - description: 'CAPTCHA site key which must be used to render a challenge for the user to solve to obtain a valid captchaResponse value. Included only when an operation was not completed because "NeedsCaptchaResponse" is true.' - end - end -end diff --git a/app/graphql/mutations/container_expiration_policies/update.rb b/app/graphql/mutations/container_expiration_policies/update.rb index db4acadfc38..762058acf3d 100644 --- a/app/graphql/mutations/container_expiration_policies/update.rb +++ b/app/graphql/mutations/container_expiration_policies/update.rb @@ -3,10 +3,10 @@ module Mutations module ContainerExpirationPolicies class Update < Mutations::BaseMutation - include FindsProject - graphql_name 'UpdateContainerExpirationPolicy' + include FindsProject + authorize :destroy_container_image argument :project_path, diff --git a/app/graphql/mutations/container_repositories/destroy_tags.rb b/app/graphql/mutations/container_repositories/destroy_tags.rb index c2737820d22..7777f903516 100644 --- a/app/graphql/mutations/container_repositories/destroy_tags.rb +++ b/app/graphql/mutations/container_repositories/destroy_tags.rb @@ -3,12 +3,11 @@ module Mutations module ContainerRepositories class DestroyTags < ::Mutations::ContainerRepositories::DestroyBase - LIMIT = 20 + graphql_name 'DestroyContainerRepositoryTags' + LIMIT = 20 TOO_MANY_TAGS_ERROR_MESSAGE = "Number of tags is greater than #{LIMIT}" - graphql_name 'DestroyContainerRepositoryTags' - authorize :destroy_container_image argument :id, diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb index ad392d6c814..269ea6c9999 100644 --- a/app/graphql/mutations/custom_emoji/create.rb +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -3,10 +3,10 @@ module Mutations module CustomEmoji class Create < BaseMutation - include Mutations::ResolvesGroup - graphql_name 'CreateCustomEmoji' + include Mutations::ResolvesGroup + authorize :create_custom_emoji field :custom_emoji, diff --git a/app/graphql/mutations/customer_relations/contacts/create.rb b/app/graphql/mutations/customer_relations/contacts/create.rb index 3495f30f227..96dc047c3db 100644 --- a/app/graphql/mutations/customer_relations/contacts/create.rb +++ b/app/graphql/mutations/customer_relations/contacts/create.rb @@ -4,11 +4,11 @@ module Mutations module CustomerRelations module Contacts class Create < BaseMutation + graphql_name 'CustomerRelationsContactCreate' + include ResolvesIds include Gitlab::Graphql::Authorize::AuthorizeResource - graphql_name 'CustomerRelationsContactCreate' - field :contact, Types::CustomerRelations::ContactType, null: true, diff --git a/app/graphql/mutations/customer_relations/contacts/update.rb b/app/graphql/mutations/customer_relations/contacts/update.rb index e2f671058f0..a3abf37f21f 100644 --- a/app/graphql/mutations/customer_relations/contacts/update.rb +++ b/app/graphql/mutations/customer_relations/contacts/update.rb @@ -4,10 +4,10 @@ module Mutations module CustomerRelations module Contacts class Update < Mutations::BaseMutation - include ResolvesIds - graphql_name 'CustomerRelationsContactUpdate' + include ResolvesIds + authorize :admin_crm_contact field :contact, diff --git a/app/graphql/mutations/customer_relations/organizations/create.rb b/app/graphql/mutations/customer_relations/organizations/create.rb index 17e0e9ad459..43c50a9fb30 100644 --- a/app/graphql/mutations/customer_relations/organizations/create.rb +++ b/app/graphql/mutations/customer_relations/organizations/create.rb @@ -4,11 +4,11 @@ module Mutations module CustomerRelations module Organizations class Create < BaseMutation + graphql_name 'CustomerRelationsOrganizationCreate' + include ResolvesIds include Gitlab::Graphql::Authorize::AuthorizeResource - graphql_name 'CustomerRelationsOrganizationCreate' - field :organization, Types::CustomerRelations::OrganizationType, null: true, diff --git a/app/graphql/mutations/customer_relations/organizations/update.rb b/app/graphql/mutations/customer_relations/organizations/update.rb index 21fcf565239..0c05541dbd7 100644 --- a/app/graphql/mutations/customer_relations/organizations/update.rb +++ b/app/graphql/mutations/customer_relations/organizations/update.rb @@ -4,10 +4,10 @@ module Mutations module CustomerRelations module Organizations class Update < Mutations::BaseMutation - include ResolvesIds - graphql_name 'CustomerRelationsOrganizationUpdate' + include ResolvesIds + authorize :admin_crm_organization field :organization, diff --git a/app/graphql/mutations/dependency_proxy/group_settings/update.rb b/app/graphql/mutations/dependency_proxy/group_settings/update.rb index d10e43cde29..65c919db3c3 100644 --- a/app/graphql/mutations/dependency_proxy/group_settings/update.rb +++ b/app/graphql/mutations/dependency_proxy/group_settings/update.rb @@ -4,10 +4,10 @@ module Mutations module DependencyProxy module GroupSettings class Update < Mutations::BaseMutation - include Mutations::ResolvesGroup - graphql_name 'UpdateDependencyProxySettings' + include Mutations::ResolvesGroup + authorize :admin_dependency_proxy argument :group_path, diff --git a/app/graphql/mutations/dependency_proxy/image_ttl_group_policy/update.rb b/app/graphql/mutations/dependency_proxy/image_ttl_group_policy/update.rb index a5eb114b2da..79d7a93c4e2 100644 --- a/app/graphql/mutations/dependency_proxy/image_ttl_group_policy/update.rb +++ b/app/graphql/mutations/dependency_proxy/image_ttl_group_policy/update.rb @@ -4,10 +4,10 @@ module Mutations module DependencyProxy module ImageTtlGroupPolicy class Update < Mutations::BaseMutation - include Mutations::ResolvesGroup - graphql_name 'UpdateDependencyProxyImageTtlGroupPolicy' + include Mutations::ResolvesGroup + authorize :admin_dependency_proxy argument :group_path, diff --git a/app/graphql/mutations/design_management/delete.rb b/app/graphql/mutations/design_management/delete.rb index 4e9f0aad934..9e643110628 100644 --- a/app/graphql/mutations/design_management/delete.rb +++ b/app/graphql/mutations/design_management/delete.rb @@ -3,10 +3,10 @@ module Mutations module DesignManagement class Delete < Base - Errors = ::Gitlab::Graphql::Errors - graphql_name "DesignManagementDelete" + Errors = ::Gitlab::Graphql::Errors + argument :filenames, [GraphQL::Types::String], required: true, description: "Filenames of the designs to delete.", diff --git a/app/graphql/mutations/groups/update.rb b/app/graphql/mutations/groups/update.rb index 9c5628a57cd..be7a14d0b43 100644 --- a/app/graphql/mutations/groups/update.rb +++ b/app/graphql/mutations/groups/update.rb @@ -3,10 +3,10 @@ module Mutations module Groups class Update < Mutations::BaseMutation - include Mutations::ResolvesGroup - graphql_name 'GroupUpdate' + include Mutations::ResolvesGroup + authorize :admin_group field :group, Types::GroupType, diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb index 72b03cc27c2..6bf8caf82d7 100644 --- a/app/graphql/mutations/issues/create.rb +++ b/app/graphql/mutations/issues/create.rb @@ -3,12 +3,12 @@ module Mutations module Issues class Create < BaseMutation + graphql_name 'CreateIssue' + include Mutations::SpamProtection include FindsProject include CommonMutationArguments - graphql_name 'CreateIssue' - authorize :create_issue argument :project_path, GraphQL::Types::ID, @@ -51,6 +51,14 @@ module Mutations required: false, description: 'Array of user IDs to assign to the issue.' + argument :move_before_id, ::Types::GlobalIDType[::Issue], + required: false, + description: 'Global ID of issue that should be placed before the current issue.' + + argument :move_after_id, ::Types::GlobalIDType[::Issue], + required: false, + description: 'Global ID of issue that should be placed after the current issue.' + field :issue, Types::IssueType, null: true, @@ -93,6 +101,13 @@ module Mutations params[:assignee_ids] &&= params[:assignee_ids].map { |assignee_id| assignee_id&.model_id } params[:label_ids] &&= params[:label_ids].map { |label_id| label_id&.model_id } + if params[:move_before_id].present? || params[:move_after_id].present? + params[:move_between_ids] = [ + params.delete(:move_before_id)&.model_id, + params.delete(:move_after_id)&.model_id + ] + end + params end diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb index 35e629ddc90..abfd6fec0bd 100644 --- a/app/graphql/mutations/issues/set_confidential.rb +++ b/app/graphql/mutations/issues/set_confidential.rb @@ -3,10 +3,10 @@ module Mutations module Issues class SetConfidential < Base - include Mutations::SpamProtection - graphql_name 'IssueSetConfidential' + include Mutations::SpamProtection + argument :confidential, GraphQL::Types::Boolean, required: true, diff --git a/app/graphql/mutations/issues/set_escalation_status.rb b/app/graphql/mutations/issues/set_escalation_status.rb index 6073b73277b..4f3fcb4886d 100644 --- a/app/graphql/mutations/issues/set_escalation_status.rb +++ b/app/graphql/mutations/issues/set_escalation_status.rb @@ -14,7 +14,7 @@ module Mutations project = issue.project authorize_escalation_status!(project) - check_feature_availability!(project, issue) + check_feature_availability!(issue) ::Issues::UpdateService.new( project: project, @@ -36,8 +36,8 @@ module Mutations raise_resource_not_available_error! end - def check_feature_availability!(project, issue) - return if Feature.enabled?(:incident_escalations, project) && issue.supports_escalation? + def check_feature_availability!(issue) + return if issue.supports_escalation? raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature unavailable for provided issue' end diff --git a/app/graphql/mutations/jira_import/import_users.rb b/app/graphql/mutations/jira_import/import_users.rb index 8d82a058dd0..b3874caee61 100644 --- a/app/graphql/mutations/jira_import/import_users.rb +++ b/app/graphql/mutations/jira_import/import_users.rb @@ -3,10 +3,10 @@ module Mutations module JiraImport class ImportUsers < BaseMutation - include FindsProject - graphql_name 'JiraImportUsers' + include FindsProject + authorize :admin_project field :jira_users, diff --git a/app/graphql/mutations/jira_import/start.rb b/app/graphql/mutations/jira_import/start.rb index 4929d6f394a..ea071c45bcf 100644 --- a/app/graphql/mutations/jira_import/start.rb +++ b/app/graphql/mutations/jira_import/start.rb @@ -3,10 +3,10 @@ module Mutations module JiraImport class Start < BaseMutation - include FindsProject - graphql_name 'JiraImportStart' + include FindsProject + authorize :admin_project field :jira_import, diff --git a/app/graphql/mutations/labels/create.rb b/app/graphql/mutations/labels/create.rb index cb3ba7939ae..3cd41dc01de 100644 --- a/app/graphql/mutations/labels/create.rb +++ b/app/graphql/mutations/labels/create.rb @@ -3,10 +3,10 @@ module Mutations module Labels class Create < BaseMutation - include Mutations::ResolvesResourceParent - graphql_name 'LabelCreate' + include Mutations::ResolvesResourceParent + field :label, Types::LabelType, null: true, diff --git a/app/graphql/mutations/merge_requests/accept.rb b/app/graphql/mutations/merge_requests/accept.rb index 7ce850901af..ebd9e2b8fdd 100644 --- a/app/graphql/mutations/merge_requests/accept.rb +++ b/app/graphql/mutations/merge_requests/accept.rb @@ -3,12 +3,6 @@ module Mutations module MergeRequests class Accept < Base - NOT_MERGEABLE = 'This branch cannot be merged' - HOOKS_VALIDATION_ERROR = 'Pre-merge hooks failed' - SHA_MISMATCH = 'The merge-head is not at the anticipated SHA' - MERGE_FAILED = 'The merge failed' - ALREADY_SCHEDULED = 'The merge request is already scheduled to be merged' - graphql_name 'MergeRequestAccept' authorize :accept_merge_request description <<~DESC @@ -17,6 +11,12 @@ module Mutations immediately if possible, or using one of the automatic merge strategies. DESC + NOT_MERGEABLE = 'This branch cannot be merged' + HOOKS_VALIDATION_ERROR = 'Pre-merge hooks failed' + SHA_MISMATCH = 'The merge-head is not at the anticipated SHA' + MERGE_FAILED = 'The merge failed' + ALREADY_SCHEDULED = 'The merge request is already scheduled to be merged' + argument :strategy, ::Types::MergeStrategyEnum, required: false, diff --git a/app/graphql/mutations/merge_requests/create.rb b/app/graphql/mutations/merge_requests/create.rb index dc1d5a22bc9..2883c02a671 100644 --- a/app/graphql/mutations/merge_requests/create.rb +++ b/app/graphql/mutations/merge_requests/create.rb @@ -3,10 +3,10 @@ module Mutations module MergeRequests class Create < BaseMutation - include FindsProject - graphql_name 'MergeRequestCreate' + include FindsProject + argument :project_path, GraphQL::Types::ID, required: true, description: 'Project full path the merge request is associated with.' diff --git a/app/graphql/mutations/namespace/package_settings/update.rb b/app/graphql/mutations/namespace/package_settings/update.rb index 400169d6b64..934b75193d7 100644 --- a/app/graphql/mutations/namespace/package_settings/update.rb +++ b/app/graphql/mutations/namespace/package_settings/update.rb @@ -4,10 +4,10 @@ module Mutations module Namespace module PackageSettings class Update < Mutations::BaseMutation - include Mutations::ResolvesNamespace - graphql_name 'UpdateNamespacePackageSettings' + include Mutations::ResolvesNamespace + authorize :create_package_settings argument :namespace_path, diff --git a/app/graphql/mutations/release_asset_links/create.rb b/app/graphql/mutations/release_asset_links/create.rb index db486640507..f6445514ce9 100644 --- a/app/graphql/mutations/release_asset_links/create.rb +++ b/app/graphql/mutations/release_asset_links/create.rb @@ -3,14 +3,13 @@ module Mutations module ReleaseAssetLinks class Create < BaseMutation - include FindsProject - graphql_name 'ReleaseAssetLinkCreate' - authorize :create_release - + include FindsProject include Types::ReleaseAssetLinkSharedInputArguments + authorize :create_release + argument :project_path, GraphQL::Types::ID, required: true, description: 'Full path of the project the asset link is associated with.' diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb index c01b0e4a01b..2921a77b86d 100644 --- a/app/graphql/mutations/snippets/create.rb +++ b/app/graphql/mutations/snippets/create.rb @@ -3,14 +3,13 @@ module Mutations module Snippets class Create < BaseMutation + graphql_name 'CreateSnippet' + include ServiceCompatibility - include CanMutateSpammable include Mutations::SpamProtection authorize :create_snippet - graphql_name 'CreateSnippet' - field :snippet, Types::SnippetType, null: true, diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb index 9ecaa8d4bf2..2a2941c5328 100644 --- a/app/graphql/mutations/snippets/update.rb +++ b/app/graphql/mutations/snippets/update.rb @@ -3,12 +3,11 @@ module Mutations module Snippets class Update < Base + graphql_name 'UpdateSnippet' + include ServiceCompatibility - include CanMutateSpammable include Mutations::SpamProtection - graphql_name 'UpdateSnippet' - argument :id, ::Types::GlobalIDType[::Snippet], required: true, description: 'Global ID of the snippet to update.' diff --git a/app/graphql/mutations/user_preferences/update.rb b/app/graphql/mutations/user_preferences/update.rb new file mode 100644 index 00000000000..c92c6d725b7 --- /dev/null +++ b/app/graphql/mutations/user_preferences/update.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Mutations + module UserPreferences + class Update < BaseMutation + graphql_name 'UserPreferencesUpdate' + + argument :issues_sort, Types::IssueSortEnum, + required: false, + description: 'Sort order for issue lists.' + + field :user_preferences, + Types::UserPreferencesType, + null: true, + description: 'User preferences after mutation.' + + def resolve(**attributes) + user_preferences = current_user.user_preference + user_preferences.update(attributes) + + { + user_preferences: user_preferences.valid? ? user_preferences : nil, + errors: errors_on_object(user_preferences) + } + end + end + end +end diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb index 88b8cefd8d2..81454db62b1 100644 --- a/app/graphql/mutations/work_items/create.rb +++ b/app/graphql/mutations/work_items/create.rb @@ -3,10 +3,13 @@ module Mutations module WorkItems class Create < BaseMutation + graphql_name 'WorkItemCreate' + include Mutations::SpamProtection include FindsProject - graphql_name 'WorkItemCreate' + description "Creates a work item." \ + " Available only when feature flag `work_items` is enabled. The feature is experimental and is subject to change without notice." authorize :create_work_item @@ -29,16 +32,21 @@ module Mutations def resolve(project_path:, **attributes) project = authorized_find!(project_path) + + unless Feature.enabled?(:work_items, project) + return { errors: ['`work_items` feature flag disabled for this project'] } + end + params = global_id_compatibility_params(attributes).merge(author_id: current_user.id) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) - work_item = ::WorkItems::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute + create_result = ::WorkItems::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute - check_spam_action_response!(work_item) + check_spam_action_response!(create_result[:work_item]) if create_result[:work_item] { - work_item: work_item.valid? ? work_item : nil, - errors: errors_on_object(work_item) + work_item: create_result.success? ? create_result[:work_item] : nil, + errors: create_result.errors } end diff --git a/app/graphql/mutations/work_items/delete.rb b/app/graphql/mutations/work_items/delete.rb new file mode 100644 index 00000000000..71792a802c0 --- /dev/null +++ b/app/graphql/mutations/work_items/delete.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class Delete < BaseMutation + graphql_name 'WorkItemDelete' + description "Deletes a work item." \ + " Available only when feature flag `work_items` is enabled. The feature is experimental and is subject to change without notice." + + authorize :delete_work_item + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, + description: 'Global ID of the work item.' + + field :project, Types::ProjectType, + null: true, + description: 'Project the deleted work item belonged to.' + + def resolve(id:) + work_item = authorized_find!(id: id) + + unless Feature.enabled?(:work_items, work_item.project) + return { errors: ['`work_items` feature flag disabled for this project'] } + end + + result = ::WorkItems::DeleteService.new( + project: work_item.project, + current_user: current_user + ).execute(work_item) + + { + project: result.success? ? work_item.project : nil, + errors: result.errors + } + end + + private + + def find_object(id:) + # TODO: Remove coercion when working on https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb new file mode 100644 index 00000000000..3ab9ba2d502 --- /dev/null +++ b/app/graphql/mutations/work_items/update.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class Update < BaseMutation + graphql_name 'WorkItemUpdate' + description "Updates a work item by Global ID." \ + " Available only when feature flag `work_items` is enabled. The feature is experimental and is subject to change without notice." + + include Mutations::SpamProtection + + authorize :update_work_item + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, + description: 'Global ID of the work item.' + argument :state_event, Types::WorkItems::StateEventEnum, + description: 'Close or reopen a work item.', + required: false + argument :title, GraphQL::Types::String, + required: false, + description: copy_field_description(Types::WorkItemType, :title) + + field :work_item, Types::WorkItemType, + null: true, + description: 'Updated work item.' + + def resolve(id:, **attributes) + work_item = authorized_find!(id: id) + + unless Feature.enabled?(:work_items, work_item.project) + return { errors: ['`work_items` feature flag disabled for this project'] } + end + + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + + ::WorkItems::UpdateService.new( + project: work_item.project, + current_user: current_user, + params: attributes, + spam_params: spam_params + ).execute(work_item) + + check_spam_action_response!(work_item) + + { + work_item: work_item.valid? ? work_item : nil, + errors: errors_on_object(work_item) + } + end + + private + + def find_object(id:) + # TODO: Remove coercion when working on https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql index 5dece2f81cc..f4921706f7e 100644 --- a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql +++ b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql @@ -120,6 +120,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { hasDetails detailsPath group + label action { __typename id diff --git a/app/graphql/resolvers/ci/project_pipeline_counts_resolver.rb b/app/graphql/resolvers/ci/project_pipeline_counts_resolver.rb new file mode 100644 index 00000000000..728bc9627c5 --- /dev/null +++ b/app/graphql/resolvers/ci/project_pipeline_counts_resolver.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Resolvers + module Ci + class ProjectPipelineCountsResolver < BaseResolver + type Types::Ci::PipelineCountsType, null: true + + argument :ref, + GraphQL::Types::String, + required: false, + description: "Filter pipelines by the ref they are run for." + + argument :sha, + GraphQL::Types::String, + required: false, + description: "Filter pipelines by the SHA of the commit they are run for." + + argument :source, + GraphQL::Types::String, + required: false, + description: "Filter pipelines by their source." + + def resolve(**args) + ::Gitlab::PipelineScopeCounts.new(context[:current_user], object, args) + end + end + end +end diff --git a/app/graphql/resolvers/ci/runner_jobs_resolver.rb b/app/graphql/resolvers/ci/runner_jobs_resolver.rb new file mode 100644 index 00000000000..2f6ca09d031 --- /dev/null +++ b/app/graphql/resolvers/ci/runner_jobs_resolver.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Resolvers + module Ci + class RunnerJobsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + include LooksAhead + + type ::Types::Ci::JobType.connection_type, null: true + authorize :read_builds + authorizes_object! + + argument :statuses, [::Types::Ci::JobStatusEnum], + required: false, + description: 'Filter jobs by status.' + + alias_method :runner, :object + + def ready?(**args) + context[self.class] ||= { executions: 0 } + context[self.class][:executions] += 1 + + raise GraphQL::ExecutionError, "Jobs can be requested for only one runner at a time" if context[self.class][:executions] > 1 + + super + end + + def resolve_with_lookahead(statuses: nil) + jobs = ::Ci::JobsFinder.new(current_user: current_user, runner: runner, params: { scope: statuses }).execute + + apply_lookahead(jobs) + end + + private + + def preloads + { + previous_stage_jobs_and_needs: [:needs, :pipeline], + artifacts: [:job_artifacts], + pipeline: [:user] + } + end + end + end +end diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb index 9848b5a503f..e221dfea4d0 100644 --- a/app/graphql/resolvers/ci/runners_resolver.rb +++ b/app/graphql/resolvers/ci/runners_resolver.rb @@ -9,7 +9,12 @@ module Resolvers argument :active, ::GraphQL::Types::Boolean, required: false, - description: 'Filter runners by active (true) or paused (false) status.' + description: 'Filter runners by `active` (true) or `paused` (false) status.', + deprecated: { reason: :renamed, replacement: 'paused', milestone: '14.8' } + + argument :paused, ::GraphQL::Types::Boolean, + required: false, + description: 'Filter runners by `paused` (true) or `active` (false) status.' argument :status, ::Types::Ci::RunnerStatusEnum, required: false, @@ -41,8 +46,11 @@ module Resolvers protected def runners_finder_params(params) + # Give preference to paused argument over the deprecated 'active' argument + paused = params.fetch(:paused, params[:active] ? !params[:active] : nil) + { - active: params[:active], + active: paused.nil? ? nil : !paused, status_status: params[:status]&.to_s, type_type: params[:type], tag_name: params[:tag_list], diff --git a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb index 8208fa56485..722fbab3bb7 100644 --- a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb +++ b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb @@ -25,7 +25,7 @@ module Resolvers private def can_read_agent_tokens? - current_user.can?(:admin_cluster, project) + current_user.can?(:read_cluster, project) end end end diff --git a/app/graphql/resolvers/kas/agent_configurations_resolver.rb b/app/graphql/resolvers/kas/agent_configurations_resolver.rb index a1b1d3bfe4c..9db104287a6 100644 --- a/app/graphql/resolvers/kas/agent_configurations_resolver.rb +++ b/app/graphql/resolvers/kas/agent_configurations_resolver.rb @@ -21,7 +21,7 @@ module Resolvers private def can_read_agent_configuration? - current_user.can?(:admin_cluster, project) + current_user.can?(:read_cluster, project) end def kas_client diff --git a/app/graphql/resolvers/kas/agent_connections_resolver.rb b/app/graphql/resolvers/kas/agent_connections_resolver.rb index 8b7c4003598..cf1a47aac75 100644 --- a/app/graphql/resolvers/kas/agent_connections_resolver.rb +++ b/app/graphql/resolvers/kas/agent_connections_resolver.rb @@ -29,7 +29,7 @@ module Resolvers def get_connected_agents kas_client.get_connected_agents(project: project) - rescue GRPC::BadStatus => e + rescue GRPC::BadStatus, Gitlab::Kas::Client::ConfigurationError => e raise Gitlab::Graphql::Errors::ResourceNotAvailable, e.class.name end diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb index 6dbcbe0e04d..72372ae6b42 100644 --- a/app/graphql/resolvers/merge_requests_resolver.rb +++ b/app/graphql/resolvers/merge_requests_resolver.rb @@ -55,6 +55,19 @@ module Resolvers required: false, description: 'Limit result to draft merge requests.' + argument :created_after, Types::TimeType, + required: false, + description: 'Merge requests created after this timestamp.' + argument :created_before, Types::TimeType, + required: false, + description: 'Merge requests created before this timestamp.' + argument :updated_after, Types::TimeType, + required: false, + description: 'Merge requests updated after this timestamp.' + argument :updated_before, Types::TimeType, + required: false, + description: 'Merge requests updated before this timestamp.' + argument :labels, [GraphQL::Types::String], required: false, as: :label_name, @@ -72,12 +85,6 @@ module Resolvers description: 'Sort merge requests by this criteria.', required: false, default_value: :created_desc - argument :created_after, Types::TimeType, - required: false, - description: 'Merge requests created after this timestamp.' - argument :created_before, Types::TimeType, - required: false, - description: 'Merge requests created before this timestamp.' negated do argument :labels, [GraphQL::Types::String], diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb index 6c0545d26de..d29d87ca204 100644 --- a/app/graphql/resolvers/paginated_tree_resolver.rb +++ b/app/graphql/resolvers/paginated_tree_resolver.rb @@ -11,14 +11,14 @@ module Resolvers required: false, default_value: '', # root of the repository description: 'Path to get the tree for. Default value is the root of the repository.' - argument :ref, GraphQL::Types::String, - required: false, - default_value: :head, - description: 'Commit ref to get the tree for. Default value is HEAD.' argument :recursive, GraphQL::Types::Boolean, required: false, default_value: false, description: 'Used to get a recursive tree. Default is false.' + argument :ref, GraphQL::Types::String, + required: false, + default_value: :head, + description: 'Commit ref to get the tree for. Default value is HEAD.' alias_method :repository, :object diff --git a/app/graphql/resolvers/project_jobs_resolver.rb b/app/graphql/resolvers/project_jobs_resolver.rb index 8a2693ee46b..b09158d475d 100644 --- a/app/graphql/resolvers/project_jobs_resolver.rb +++ b/app/graphql/resolvers/project_jobs_resolver.rb @@ -18,7 +18,8 @@ module Resolvers def ready?(**args) context[self.class] ||= { executions: 0 } context[self.class][:executions] += 1 - raise GraphQL::ExecutionError, "Jobs can only be requested for one project at a time" if context[self.class][:executions] > 1 + + raise GraphQL::ExecutionError, "Jobs can be requested for only one project at a time" if context[self.class][:executions] > 1 super end diff --git a/app/graphql/resolvers/recent_boards_resolver.rb b/app/graphql/resolvers/recent_boards_resolver.rb new file mode 100644 index 00000000000..4de5b8f072b --- /dev/null +++ b/app/graphql/resolvers/recent_boards_resolver.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Resolvers + class RecentBoardsResolver < BaseResolver + type Types::BoardType, null: true + + def resolve + parent = object.respond_to?(:sync) ? object.sync : object + return Board.none unless parent + + recent_visits = + ::Boards::VisitsFinder.new(parent, current_user).latest(Board::RECENT_BOARDS_SIZE) + + recent_visits&.map(&:board) || [] + end + end +end diff --git a/app/graphql/resolvers/tree_resolver.rb b/app/graphql/resolvers/tree_resolver.rb index 8d6ece0956e..f02eb226810 100644 --- a/app/graphql/resolvers/tree_resolver.rb +++ b/app/graphql/resolvers/tree_resolver.rb @@ -10,14 +10,14 @@ module Resolvers required: false, default_value: '', description: 'Path to get the tree for. Default value is the root of the repository.' - argument :ref, GraphQL::Types::String, - required: false, - default_value: :head, - description: 'Commit ref to get the tree for. Default value is HEAD.' argument :recursive, GraphQL::Types::Boolean, required: false, default_value: false, description: 'Used to get a recursive tree. Default is false.' + argument :ref, GraphQL::Types::String, + required: false, + default_value: :head, + description: 'Commit ref to get the tree for. Default value is HEAD.' alias_method :repository, :object diff --git a/app/graphql/resolvers/users/groups_resolver.rb b/app/graphql/resolvers/users/groups_resolver.rb index d8492a8fcf9..09c6b51cc3d 100644 --- a/app/graphql/resolvers/users/groups_resolver.rb +++ b/app/graphql/resolvers/users/groups_resolver.rb @@ -11,13 +11,13 @@ module Resolvers authorize :read_user_groups authorizes_object! - argument :search, GraphQL::Types::String, - required: false, - description: 'Search by group name or path.' argument :permission_scope, ::Types::PermissionTypes::GroupEnum, required: false, description: 'Filter by permissions the user has on groups.' + argument :search, GraphQL::Types::String, + required: false, + description: 'Search by group name or path.' before_connection_authorization do |nodes, current_user| Preloaders::GroupPolicyPreloader.new(nodes, current_user).execute diff --git a/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb b/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb index 8276549ddcc..1fc47303d67 100644 --- a/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb +++ b/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb @@ -5,10 +5,11 @@ module Types module Analytics module UsageTrends class MeasurementType < BaseObject - include Gitlab::Graphql::Authorize::AuthorizeResource graphql_name 'UsageTrendsMeasurement' description 'Represents a recorded measurement (object count) for the Admins' + include Gitlab::Graphql::Authorize::AuthorizeResource + authorize :read_usage_trends_measurement field :recorded_at, Types::TimeType, null: true, diff --git a/app/graphql/types/alert_management/prometheus_integration_type.rb b/app/graphql/types/alert_management/prometheus_integration_type.rb index 27e4832d8f6..9a2ef78eca7 100644 --- a/app/graphql/types/alert_management/prometheus_integration_type.rb +++ b/app/graphql/types/alert_management/prometheus_integration_type.rb @@ -3,11 +3,11 @@ module Types module AlertManagement class PrometheusIntegrationType < ::Types::BaseObject - include ::Gitlab::Routing - graphql_name 'AlertManagementPrometheusIntegration' description 'An endpoint and credentials used to accept Prometheus alerts for a project' + include ::Gitlab::Routing + implements(Types::AlertManagement::IntegrationType) authorize :admin_project diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb index 8c67803e39e..733006369ea 100644 --- a/app/graphql/types/board_list_type.rb +++ b/app/graphql/types/board_list_type.rb @@ -3,11 +3,11 @@ module Types # rubocop: disable Graphql/AuthorizeTypes class BoardListType < BaseObject - include Gitlab::Utils::StrongMemoize - graphql_name 'BoardList' description 'Represents a list for an issue board' + include Gitlab::Utils::StrongMemoize + alias_method :list, :object field :id, GraphQL::Types::ID, diff --git a/app/graphql/types/ci/pipeline_counts_type.rb b/app/graphql/types/ci/pipeline_counts_type.rb new file mode 100644 index 00000000000..9c2b822091e --- /dev/null +++ b/app/graphql/types/ci/pipeline_counts_type.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Types + module Ci + class PipelineCountsType < BaseObject + graphql_name 'PipelineCounts' + description "Represents pipeline counts for the project" + + authorize :read_pipeline + + (::Types::Ci::PipelineScopeEnum.values.keys - %w[BRANCHES TAGS]).each do |scope| + field scope.downcase, + GraphQL::Types::Int, + null: true, + description: "Number of pipelines with scope #{scope} for the project" + end + + field :all, + GraphQL::Types::Int, + null: true, + description: 'Total number of pipelines for the project.' + end + end +end diff --git a/app/graphql/types/ci/runner_sort_enum.rb b/app/graphql/types/ci/runner_sort_enum.rb index 95ec1867fea..8f2a13bd699 100644 --- a/app/graphql/types/ci/runner_sort_enum.rb +++ b/app/graphql/types/ci/runner_sort_enum.rb @@ -10,6 +10,8 @@ module Types value 'CONTACTED_DESC', 'Ordered by contacted_at in descending order.', value: :contacted_desc value 'CREATED_ASC', 'Ordered by created_at in ascending order.', value: :created_at_asc value 'CREATED_DESC', 'Ordered by created_at in descending order.', value: :created_at_desc + value 'TOKEN_EXPIRES_AT_ASC', 'Ordered by token_expires_at in ascending order.', value: :token_expires_at_asc + value 'TOKEN_EXPIRES_AT_DESC', 'Ordered by token_expires_at in descending order.', value: :token_expires_at_desc end end end diff --git a/app/graphql/types/ci/runner_status_enum.rb b/app/graphql/types/ci/runner_status_enum.rb index dd056191ceb..2e65e2d4e1e 100644 --- a/app/graphql/types/ci/runner_status_enum.rb +++ b/app/graphql/types/ci/runner_status_enum.rb @@ -7,12 +7,20 @@ module Types value 'ACTIVE', description: 'Runner that is not paused.', - deprecated: { reason: 'Use CiRunnerType.active instead', milestone: '14.6' }, + deprecated: { + reason: :renamed, + replacement: 'CiRunner.paused', + milestone: '14.6' + }, value: :active value 'PAUSED', description: 'Runner that is paused.', - deprecated: { reason: 'Use CiRunnerType.active instead', milestone: '14.6' }, + deprecated: { + reason: :renamed, + replacement: 'CiRunner.paused', + milestone: '14.6' + }, value: :paused value 'ONLINE', diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 4fe65734911..9094c6b96e4 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -3,12 +3,13 @@ module Types module Ci class RunnerType < BaseObject + graphql_name 'CiRunner' + edge_type_class(RunnerWebUrlEdge) connection_type_class(Types::CountableConnectionType) - graphql_name 'CiRunner' + authorize :read_runner present_using ::Ci::RunnerPresenter - expose_permissions Types::PermissionTypes::Ci::Runner JOB_COUNT_LIMIT = 1000 @@ -24,12 +25,18 @@ module Types field :contacted_at, Types::TimeType, null: true, description: 'Timestamp of last contact from this runner.', method: :contacted_at + field :token_expires_at, Types::TimeType, null: true, + description: 'Runner token expiration time.', + method: :token_expires_at field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' field :access_level, ::Types::Ci::RunnerAccessLevelEnum, null: false, description: 'Access level of the runner.' field :active, GraphQL::Types::Boolean, null: false, - description: 'Indicates the runner is allowed to receive jobs.' + description: 'Indicates the runner is allowed to receive jobs.', + deprecated: { reason: 'Use paused', milestone: '14.8' } + field :paused, GraphQL::Types::Boolean, null: false, + description: 'Indicates the runner is paused and not available to run jobs.' field :status, Types::Ci::RunnerStatusEnum, null: false, @@ -63,6 +70,14 @@ module Types description: 'Executor last advertised by the runner.', method: :executor_name, feature_flag: :graphql_ci_runner_executor + field :groups, ::Types::GroupType.connection_type, null: true, + description: 'Groups the runner is associated with. For group runners only.' + field :projects, ::Types::ProjectType.connection_type, null: true, + description: 'Projects the runner is associated with. For project runners only.' + field :jobs, ::Types::Ci::JobType.connection_type, null: true, + description: 'Jobs assigned to the runner.', + authorize: :read_builds, + resolver: ::Resolvers::Ci::RunnerJobsResolver def job_count # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT @@ -94,11 +109,40 @@ module Types end # rubocop: enable CodeReuse/ActiveRecord + def groups + return unless runner.group_type? + + batched_owners(::Ci::RunnerNamespace, Group, :runner_groups, :namespace_id) + end + + def projects + return unless runner.project_type? + + batched_owners(::Ci::RunnerProject, Project, :runner_projects, :project_id) + end + private def can_admin_runners? context[:current_user]&.can_admin_all_resources? end + + # rubocop: disable CodeReuse/ActiveRecord + def batched_owners(runner_assoc_type, assoc_type, key, column_name) + BatchLoader::GraphQL.for(runner.id).batch(key: key) do |runner_ids, loader, args| + runner_and_owner_ids = runner_assoc_type.where(runner_id: runner_ids).pluck(:runner_id, column_name) + + owner_ids_by_runner_id = runner_and_owner_ids.group_by(&:first).transform_values { |v| v.pluck(1) } + owner_ids = runner_and_owner_ids.pluck(1).uniq + + owners = assoc_type.where(id: owner_ids).index_by(&:id) + + runner_ids.each do |runner_id| + loader.call(runner_id, owner_ids_by_runner_id[runner_id]&.map { |owner_id| owners[owner_id] } || []) + end + end + end + # rubocop: enable CodeReuse/ActiveRecord end end end diff --git a/app/graphql/types/clusters/agent_activity_event_type.rb b/app/graphql/types/clusters/agent_activity_event_type.rb index 79a9fd70505..3484acfe25e 100644 --- a/app/graphql/types/clusters/agent_activity_event_type.rb +++ b/app/graphql/types/clusters/agent_activity_event_type.rb @@ -5,7 +5,7 @@ module Types class AgentActivityEventType < BaseObject graphql_name 'ClusterAgentActivityEvent' - authorize :admin_cluster + authorize :read_cluster connection_type_class(Types::CountableConnectionType) diff --git a/app/graphql/types/clusters/agent_token_type.rb b/app/graphql/types/clusters/agent_token_type.rb index 96fdb5f05c8..24489707698 100644 --- a/app/graphql/types/clusters/agent_token_type.rb +++ b/app/graphql/types/clusters/agent_token_type.rb @@ -5,7 +5,7 @@ module Types class AgentTokenType < BaseObject graphql_name 'ClusterAgentToken' - authorize :admin_cluster + authorize :read_cluster connection_type_class(Types::CountableConnectionType) diff --git a/app/graphql/types/clusters/agent_type.rb b/app/graphql/types/clusters/agent_type.rb index 89316ed4728..546252b2285 100644 --- a/app/graphql/types/clusters/agent_type.rb +++ b/app/graphql/types/clusters/agent_type.rb @@ -5,7 +5,7 @@ module Types class AgentType < BaseObject graphql_name 'ClusterAgent' - authorize :admin_cluster + authorize :read_cluster connection_type_class(Types::CountableConnectionType) diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index 2584e15ff0b..8bc00359ccb 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -10,33 +10,37 @@ module Types field :id, type: GraphQL::Types::ID, null: false, description: 'ID (global ID) of the commit.' + field :sha, type: GraphQL::Types::String, null: false, description: 'SHA1 ID of the commit.' + field :short_id, type: GraphQL::Types::String, null: false, description: 'Short SHA1 ID of the commit.' field :title, type: GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Title of the commit message.' - markdown_field :title_html, null: true field :full_title, type: GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Full title of the commit message.' - markdown_field :full_title_html, null: true field :description, type: GraphQL::Types::String, null: true, description: 'Description of the commit message.' - markdown_field :description_html, null: true field :message, type: GraphQL::Types::String, null: true, description: 'Raw commit message.' + field :authored_date, type: Types::TimeType, null: true, description: 'Timestamp of when the commit was authored.' + field :web_url, type: GraphQL::Types::String, null: false, description: 'Web URL of the commit.' + field :web_path, type: GraphQL::Types::String, null: false, description: 'Web path of the commit.' + field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Rendered HTML of the commit signature.' + field :author_name, type: GraphQL::Types::String, null: true, description: 'Commit authors name.' field :author_email, type: GraphQL::Types::String, null: true, @@ -53,6 +57,10 @@ module Types description: 'Pipelines of the commit ordered latest first.', resolver: Resolvers::CommitPipelinesResolver + markdown_field :title_html, null: true + markdown_field :full_title_html, null: true + markdown_field :description_html, null: true + def author_gravatar GravatarService.new.execute(object.author_email, 40) end diff --git a/app/graphql/types/group_invitation_type.rb b/app/graphql/types/group_invitation_type.rb index 9410253553c..48281dcfd9f 100644 --- a/app/graphql/types/group_invitation_type.rb +++ b/app/graphql/types/group_invitation_type.rb @@ -2,14 +2,14 @@ module Types class GroupInvitationType < BaseObject + graphql_name 'GroupInvitation' + description 'Represents a Group Invitation' + expose_permissions Types::PermissionTypes::Group authorize :admin_group implements InvitationInterface - graphql_name 'GroupInvitation' - description 'Represents a Group Invitation' - field :group, Types::GroupType, null: true, description: 'Group that a User is invited to.' diff --git a/app/graphql/types/group_member_type.rb b/app/graphql/types/group_member_type.rb index 8b8e69d795d..d68abc11bba 100644 --- a/app/graphql/types/group_member_type.rb +++ b/app/graphql/types/group_member_type.rb @@ -2,14 +2,14 @@ module Types class GroupMemberType < BaseObject + graphql_name 'GroupMember' + description 'Represents a Group Membership' + expose_permissions Types::PermissionTypes::Group authorize :read_group implements MemberInterface - graphql_name 'GroupMember' - description 'Represents a Group Membership' - field :group, Types::GroupType, null: true, description: 'Group that a User is a member of.' diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index e02650fd285..5f63aa20953 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -94,6 +94,12 @@ module Types max_page_size: 2000, resolver: Resolvers::BoardsResolver + field :recent_issue_boards, + Types::BoardType.connection_type, + null: true, + description: 'List of recently visited boards of the group. Maximum size is 4.', + resolver: Resolvers::RecentBoardsResolver + field :board, Types::BoardType, null: true, @@ -170,15 +176,6 @@ module Types null: true, description: 'Dependency proxy TTL policy for the group.' - def label(title:) - BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| - LabelsFinder - .new(current_user, group: args[:key], title: titles) - .execute - .each { |label| loader.call(label.title, label) } - end - end - field :labels, Types::LabelType.connection_type, null: true, @@ -215,6 +212,15 @@ module Types description: 'Work item types available to the group.', feature_flag: :work_items + def label(title:) + BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| + LabelsFinder + .new(current_user, group: args[:key], title: titles) + .execute + .each { |label| loader.call(label.title, label) } + end + end + def avatar_url object.avatar_url(only_path: false) end diff --git a/app/graphql/types/issuable_type.rb b/app/graphql/types/issuable_type.rb index 6ca74087f8a..4a39b5ed6ec 100644 --- a/app/graphql/types/issuable_type.rb +++ b/app/graphql/types/issuable_type.rb @@ -5,10 +5,12 @@ module Types graphql_name 'Issuable' description 'Represents an issuable.' - possible_types Types::IssueType, Types::MergeRequestType + possible_types Types::IssueType, Types::MergeRequestType, Types::WorkItemType def self.resolve_type(object, context) case object + when WorkItem + Types::WorkItemType when Issue Types::IssueType when MergeRequest diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 46fe91feae4..ee57961ee4a 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -21,10 +21,8 @@ module Types description: "Internal ID of the issue." field :title, GraphQL::Types::String, null: false, description: 'Title of the issue.' - markdown_field :title_html, null: true field :description, GraphQL::Types::String, null: true, description: 'Description of the issue.' - markdown_field :description_html, null: true field :state, IssueStateEnum, null: false, description: 'State of the issue.' @@ -143,6 +141,9 @@ module Types field :escalation_status, Types::IncidentManagement::EscalationStatusEnum, null: true, description: 'Escalation status of the issue.' + markdown_field :title_html, null: true + markdown_field :description_html, null: true + def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end @@ -168,13 +169,11 @@ module Types end def hidden? - object.hidden? if Feature.enabled?(:ban_user_feature_flag) + object.hidden? if Feature.enabled?(:ban_user_feature_flag, default_enabled: :yaml) end def escalation_status - return unless Feature.enabled?(:incident_escalations, object.project) && object.supports_escalation? - - object.escalation_status&.status_name + object.supports_escalation? ? object.escalation_status&.status_name : nil end end end diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index bb2d561014e..5a10bcfee74 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -12,7 +12,6 @@ module Types description: 'Label ID.' field :description, GraphQL::Types::String, null: true, description: 'Description of the label (Markdown rendered as HTML for caching).' - markdown_field :description_html, null: true field :title, GraphQL::Types::String, null: false, description: 'Content of the label.' field :color, GraphQL::Types::String, null: false, @@ -23,5 +22,7 @@ module Types description: 'When this label was created.' field :updated_at, Types::TimeType, null: false, description: 'When this label was last updated.' + + markdown_field :description_html, null: true end end diff --git a/app/graphql/types/member_interface.rb b/app/graphql/types/member_interface.rb index c5623cd4710..67d0e18b522 100644 --- a/app/graphql/types/member_interface.rb +++ b/app/graphql/types/member_interface.rb @@ -25,6 +25,12 @@ module Types field :user, Types::UserType, null: true, description: 'User that is associated with the member object.' + field :merge_request_interaction, Types::UserMergeRequestInteractionType, + null: true, + description: 'Find a merge request.' do + argument :id, ::Types::GlobalIDType[::MergeRequest], required: true, description: 'Global ID of the merge request.' + end + definition_methods do def resolve_type(object, context) case object @@ -37,5 +43,11 @@ module Types end end end + + def merge_request_interaction(id: nil) + Gitlab::Graphql::Lazy.with_value(GitlabSchema.object_from_id(id, expected_class: ::MergeRequest)) do |merge_request| + Users::MergeRequestInteraction.new(user: object.user, merge_request: merge_request) if merge_request + end + end end end diff --git a/app/graphql/types/merge_request_sort_enum.rb b/app/graphql/types/merge_request_sort_enum.rb index d75eae6abc4..a74c5a01769 100644 --- a/app/graphql/types/merge_request_sort_enum.rb +++ b/app/graphql/types/merge_request_sort_enum.rb @@ -9,5 +9,7 @@ module Types value 'MERGED_AT_DESC', 'Merge time by descending order.', value: :merged_at_desc value 'CLOSED_AT_ASC', 'Closed time by ascending order.', value: :closed_at_asc value 'CLOSED_AT_DESC', 'Closed time by descending order.', value: :closed_at_desc + value 'TITLE_ASC', 'Title by ascending order.', value: :title_asc + value 'TITLE_DESC', 'Title by descending order.', value: :title_desc end end diff --git a/app/graphql/types/merge_requests/assignee_type.rb b/app/graphql/types/merge_requests/assignee_type.rb index 8448477370e..24321d057a3 100644 --- a/app/graphql/types/merge_requests/assignee_type.rb +++ b/app/graphql/types/merge_requests/assignee_type.rb @@ -3,11 +3,12 @@ module Types module MergeRequests class AssigneeType < ::Types::UserType + graphql_name 'MergeRequestAssignee' + description 'A user assigned to a merge request.' + include FindClosest include ::Types::MergeRequests::InteractsWithMergeRequest - graphql_name 'MergeRequestAssignee' - description 'A user assigned to a merge request.' authorize :read_user end end diff --git a/app/graphql/types/merge_requests/interacts_with_merge_request.rb b/app/graphql/types/merge_requests/interacts_with_merge_request.rb index d4a1f2faa8d..15621ef1472 100644 --- a/app/graphql/types/merge_requests/interacts_with_merge_request.rb +++ b/app/graphql/types/merge_requests/interacts_with_merge_request.rb @@ -5,6 +5,8 @@ module Types module InteractsWithMergeRequest extend ActiveSupport::Concern + include FindClosest + included do field :merge_request_interaction, type: ::Types::UserMergeRequestInteractionType, @@ -13,8 +15,9 @@ module Types description: "Details of this user's interactions with the merge request." end - def merge_request_interaction(parent:) + def merge_request_interaction(parent:, id: nil) merge_request = closest_parent([::Types::MergeRequestType], parent) + return unless merge_request Users::MergeRequestInteraction.new(user: object, merge_request: merge_request) diff --git a/app/graphql/types/merge_requests/reviewer_type.rb b/app/graphql/types/merge_requests/reviewer_type.rb index 1ced821c839..11f7ceaf461 100644 --- a/app/graphql/types/merge_requests/reviewer_type.rb +++ b/app/graphql/types/merge_requests/reviewer_type.rb @@ -3,11 +3,12 @@ module Types module MergeRequests class ReviewerType < ::Types::UserType + graphql_name 'MergeRequestReviewer' + description 'A user assigned to a merge request as a reviewer.' + include FindClosest include ::Types::MergeRequests::InteractsWithMergeRequest - graphql_name 'MergeRequestReviewer' - description 'A user assigned to a merge request as a reviewer.' authorize :read_user end end diff --git a/app/graphql/types/metrics/dashboards/annotation_type.rb b/app/graphql/types/metrics/dashboards/annotation_type.rb index fb35f2bd9a1..0c787476f54 100644 --- a/app/graphql/types/metrics/dashboards/annotation_type.rb +++ b/app/graphql/types/metrics/dashboards/annotation_type.rb @@ -4,8 +4,8 @@ module Types module Metrics module Dashboards class AnnotationType < ::Types::BaseObject - authorize :read_metrics_dashboard_annotation graphql_name 'MetricsDashboardAnnotation' + authorize :read_metrics_dashboard_annotation field :description, GraphQL::Types::String, null: true, description: 'Description of the annotation.' diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index c350f4dd922..3c735231595 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -2,10 +2,10 @@ module Types class MutationType < BaseObject - include Gitlab::Graphql::MountMutation - graphql_name 'Mutation' + include Gitlab::Graphql::MountMutation + mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs mount_mutation Mutations::AlertManagement::CreateAlertIssue mount_mutation Mutations::AlertManagement::UpdateAlertStatus @@ -121,10 +121,13 @@ module Types mount_mutation Mutations::Namespace::PackageSettings::Update mount_mutation Mutations::Groups::Update mount_mutation Mutations::UserCallouts::Create + mount_mutation Mutations::UserPreferences::Update mount_mutation Mutations::Packages::Destroy mount_mutation Mutations::Packages::DestroyFile mount_mutation Mutations::Echo - mount_mutation Mutations::WorkItems::Create, feature_flag: :work_items + mount_mutation Mutations::WorkItems::Create + mount_mutation Mutations::WorkItems::Delete + mount_mutation Mutations::WorkItems::Update end end diff --git a/app/graphql/types/notes/discussion_type.rb b/app/graphql/types/notes/discussion_type.rb index 56579c357a7..ffe61c9ff88 100644 --- a/app/graphql/types/notes/discussion_type.rb +++ b/app/graphql/types/notes/discussion_type.rb @@ -3,10 +3,10 @@ module Types module Notes class DiscussionType < BaseObject - DiscussionID = ::Types::GlobalIDType[::Discussion] - graphql_name 'Discussion' + DiscussionID = ::Types::GlobalIDType[::Discussion] + authorize :read_note implements(Types::ResolvableInterface) diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index 1d2cf9649d8..444ecb5e792 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -3,16 +3,17 @@ module Types module Packages class PackageDetailsType < PackageType - include ::PackagesHelper - graphql_name 'PackageDetailsType' description 'Represents a package details in the Package Registry. Note that this type is in beta and susceptible to changes' + + include ::PackagesHelper + authorize :read_package field :versions, ::Types::Packages::PackageType.connection_type, null: true, description: 'Other versions of the package.' - field :package_files, Types::Packages::PackageFileType.connection_type, null: true, description: 'Package files.' + field :package_files, Types::Packages::PackageFileType.connection_type, null: true, method: :installable_package_files, description: 'Package files.' field :dependency_links, Types::Packages::PackageDependencyLinkType.connection_type, null: true, description: 'Dependency link.' @@ -36,14 +37,6 @@ module Types object.versions end - def package_files - if Feature.enabled?(:packages_installable_package_files, default_enabled: :yaml) - object.installable_package_files - else - object.package_files - end - end - def composer_config_repository_url composer_config_repository_name(object.project.group&.id) end diff --git a/app/graphql/types/permission_types/issue.rb b/app/graphql/types/permission_types/issue.rb index 94e1bffd685..b38971b64cd 100644 --- a/app/graphql/types/permission_types/issue.rb +++ b/app/graphql/types/permission_types/issue.rb @@ -3,8 +3,8 @@ module Types module PermissionTypes class Issue < BasePermissionType - description 'Check permissions for the current user on a issue' graphql_name 'IssuePermissions' + description 'Check permissions for the current user on a issue' abilities :read_issue, :admin_issue, :update_issue, :reopen_issue, :read_design, :create_design, :destroy_design, diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb index 52c11fe5588..73a2f820f79 100644 --- a/app/graphql/types/permission_types/merge_request.rb +++ b/app/graphql/types/permission_types/merge_request.rb @@ -3,15 +3,16 @@ module Types module PermissionTypes class MergeRequest < BasePermissionType + graphql_name 'MergeRequestPermissions' + description 'Check permissions for the current user on a merge request' + + present_using MergeRequestPresenter + PERMISSION_FIELDS = %i[push_to_source_branch remove_source_branch cherry_pick_on_current_merge_request revert_on_current_merge_request].freeze - present_using MergeRequestPresenter - description 'Check permissions for the current user on a merge request' - graphql_name 'MergeRequestPermissions' - abilities :read_merge_request, :admin_merge_request, :update_merge_request, :create_note diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index d49244f6b65..dc428e7bdce 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -15,6 +15,8 @@ module Types description: 'Full path of the project.' field :path, GraphQL::Types::String, null: false, description: 'Path of the project.' + field :ci_config_path_or_default, GraphQL::Types::String, null: false, + description: 'Path of the CI configuration file.' field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, null: true, calls_gitaly: true, @@ -195,6 +197,12 @@ module Types extras: [:lookahead], resolver: Resolvers::ProjectPipelineResolver + field :pipeline_counts, + Types::Ci::PipelineCountsType, + null: true, + description: 'Build pipeline counts of the project.', + resolver: Resolvers::Ci::ProjectPipelineCountsResolver + field :ci_cd_settings, Types::Ci::CiCdSettingType, null: true, @@ -231,6 +239,12 @@ module Types max_page_size: 2000, resolver: Resolvers::BoardsResolver + field :recent_issue_boards, + Types::BoardType.connection_type, + null: true, + description: 'List of recently visited boards of the project. Maximum size is 4.', + resolver: Resolvers::RecentBoardsResolver + field :board, Types::BoardType, null: true, diff --git a/app/graphql/types/query_complexity_type.rb b/app/graphql/types/query_complexity_type.rb index 3f58a15aef7..13b618cf5ce 100644 --- a/app/graphql/types/query_complexity_type.rb +++ b/app/graphql/types/query_complexity_type.rb @@ -3,10 +3,10 @@ module Types # rubocop: disable Graphql/AuthorizeTypes class QueryComplexityType < ::Types::BaseObject - ANALYZER = GraphQL::Analysis::QueryComplexity.new { |_query, complexity| complexity } - graphql_name 'QueryComplexity' + ANALYZER = GraphQL::Analysis::QueryComplexity.new { |_query, complexity| complexity } + alias_method :query, :object field :limit, GraphQL::Types::Int, diff --git a/app/graphql/types/repository/blob_type.rb b/app/graphql/types/repository/blob_type.rb index 28339093172..bfd59763a07 100644 --- a/app/graphql/types/repository/blob_type.rb +++ b/app/graphql/types/repository/blob_type.rb @@ -4,10 +4,10 @@ module Types # rubocop: disable Graphql/AuthorizeTypes # This is presented through `Repository` that has its own authorization class BlobType < BaseObject - present_using BlobPresenter - graphql_name 'RepositoryBlob' + present_using BlobPresenter + field :id, GraphQL::Types::ID, null: false, description: 'ID of the blob.' @@ -87,6 +87,14 @@ module Types description: 'Web path to blob permalink.', calls_gitaly: true + field :environment_formatted_external_url, GraphQL::Types::String, null: true, + description: 'Environment on which the blob is available.', + calls_gitaly: true + + field :environment_external_url_for_route_map, GraphQL::Types::String, null: true, + description: 'Web path to blob on an environment.', + calls_gitaly: true + field :code_owners, [Types::UserType], null: true, description: 'List of code owners for the blob.', calls_gitaly: true @@ -117,6 +125,12 @@ module Types field :archived, GraphQL::Types::Boolean, null: true, method: :archived?, description: 'Whether the current project is archived.' + field :language, GraphQL::Types::String, + description: 'Blob language.', + method: :blob_language, + null: true, + calls_gitaly: true + def raw_text_blob object.data unless object.binary? end diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb index 88dc6036bfd..4dcadf1274f 100644 --- a/app/graphql/types/root_storage_statistics_type.rb +++ b/app/graphql/types/root_storage_statistics_type.rb @@ -15,5 +15,6 @@ module Types field :snippets_size, GraphQL::Types::Float, null: false, description: 'Snippets size in bytes.' field :pipeline_artifacts_size, GraphQL::Types::Float, null: false, description: 'CI pipeline artifacts size in bytes.' field :uploads_size, GraphQL::Types::Float, null: false, description: 'Uploads size in bytes.' + field :dependency_proxy_size, GraphQL::Types::Float, null: false, description: 'Dependency Proxy sizes in bytes.' end end diff --git a/app/graphql/types/subscription_type.rb b/app/graphql/types/subscription_type.rb index 3629edb5b33..db6a247179d 100644 --- a/app/graphql/types/subscription_type.rb +++ b/app/graphql/types/subscription_type.rb @@ -9,5 +9,8 @@ module Types field :issue_crm_contacts_updated, subscription: Subscriptions::IssuableUpdated, null: true, description: 'Triggered when the crm contacts of an issuable are updated.' + + field :issuable_title_updated, subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the title of an issuable is updated.' end end diff --git a/app/graphql/types/terraform/state_version_type.rb b/app/graphql/types/terraform/state_version_type.rb index bf1af4565bc..59da550aa1b 100644 --- a/app/graphql/types/terraform/state_version_type.rb +++ b/app/graphql/types/terraform/state_version_type.rb @@ -3,10 +3,10 @@ module Types module Terraform class StateVersionType < BaseObject - include ::API::Helpers::RelatedResourcesHelpers - graphql_name 'TerraformStateVersion' + include ::API::Helpers::RelatedResourcesHelpers + authorize :read_terraform_state field :id, GraphQL::Types::ID, diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb index bb15d91a62f..bcff65be652 100644 --- a/app/graphql/types/tree/blob_type.rb +++ b/app/graphql/types/tree/blob_type.rb @@ -4,12 +4,11 @@ module Types # rubocop: disable Graphql/AuthorizeTypes # This is presented through `Repository` that has its own authorization class BlobType < BaseObject - implements Types::Tree::EntryType + graphql_name 'Blob' + implements Types::Tree::EntryType present_using BlobPresenter - graphql_name 'Blob' - field :web_url, GraphQL::Types::String, null: true, description: 'Web URL of the blob.' field :web_path, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/tree/submodule_type.rb b/app/graphql/types/tree/submodule_type.rb index 05d8c1a951a..bc7828dbffa 100644 --- a/app/graphql/types/tree/submodule_type.rb +++ b/app/graphql/types/tree/submodule_type.rb @@ -4,10 +4,10 @@ module Types # rubocop: disable Graphql/AuthorizeTypes # This is presented through `Repository` that has its own authorization class SubmoduleType < BaseObject - implements Types::Tree::EntryType - graphql_name 'Submodule' + implements Types::Tree::EntryType + field :web_url, type: GraphQL::Types::String, null: true, description: 'Web URL for the sub-module.' field :tree_url, type: GraphQL::Types::String, null: true, diff --git a/app/graphql/types/tree/tree_entry_type.rb b/app/graphql/types/tree/tree_entry_type.rb index 998b3617574..cdc84c8e318 100644 --- a/app/graphql/types/tree/tree_entry_type.rb +++ b/app/graphql/types/tree/tree_entry_type.rb @@ -4,13 +4,12 @@ module Types # rubocop: disable Graphql/AuthorizeTypes # This is presented through `Repository` that has its own authorization class TreeEntryType < BaseObject - implements Types::Tree::EntryType - - present_using TreeEntryPresenter - graphql_name 'TreeEntry' description 'Represents a directory' + implements Types::Tree::EntryType + present_using TreeEntryPresenter + field :web_url, GraphQL::Types::String, null: true, description: 'Web URL for the tree entry (directory).' field :web_path, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index 6bb4cb29cdd..24fca80d5a9 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -31,7 +31,7 @@ module Types null: false, resolver_method: :redacted_name, description: 'Human-readable name of the user. ' \ - 'Will return `****` if the user is a project bot and the requester does not have permission to read resource access tokens.' + 'Returns `****` if the user is a project bot and the requester does not have permission to view the project.' field :state, type: Types::UserStateEnum, @@ -127,7 +127,7 @@ module Types def redacted_name return object.name unless object.project_bot? - return object.name if context[:current_user]&.can?(:read_resource_access_tokens, object.projects.first) + return object.name if context[:current_user]&.can?(:read_project, object.projects.first) # If the requester does not have permission to read the project bot name, # the API returns an arbitrary string. UI changes will be addressed in a follow up issue: diff --git a/app/graphql/types/user_preferences_type.rb b/app/graphql/types/user_preferences_type.rb new file mode 100644 index 00000000000..9a1ea4a2e4f --- /dev/null +++ b/app/graphql/types/user_preferences_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + # Only used to render the current user's own preferences + class UserPreferencesType < BaseObject + graphql_name 'UserPreferences' + + field :issues_sort, Types::IssueSortEnum, + description: 'Sort order for issue lists.', + null: true + + def issues_sort + object.issues_sort.to_sym + end + end +end diff --git a/app/graphql/types/work_item_state_enum.rb b/app/graphql/types/work_item_state_enum.rb new file mode 100644 index 00000000000..8fe58f76d9a --- /dev/null +++ b/app/graphql/types/work_item_state_enum.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + class WorkItemStateEnum < BaseEnum + graphql_name 'WorkItemState' + description 'State of a GitLab work item' + + value 'OPEN', 'In open state.', value: 'opened' + value 'CLOSED', 'In closed state.', value: 'closed' + end +end diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb index 486c1e52987..15a5557b489 100644 --- a/app/graphql/types/work_item_type.rb +++ b/app/graphql/types/work_item_type.rb @@ -12,6 +12,8 @@ module Types description: 'Global ID of the work item.' field :iid, GraphQL::Types::ID, null: false, description: 'Internal ID of the work item.' + field :state, WorkItemStateEnum, null: false, + description: 'State of the work item.' field :title, GraphQL::Types::String, null: false, description: 'Title of the work item.' field :work_item_type, Types::WorkItems::TypeType, null: false, diff --git a/app/graphql/types/work_items/state_event_enum.rb b/app/graphql/types/work_items/state_event_enum.rb new file mode 100644 index 00000000000..db54d494c12 --- /dev/null +++ b/app/graphql/types/work_items/state_event_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module WorkItems + class StateEventEnum < BaseEnum + graphql_name 'WorkItemStateEvent' + description 'Values for work item state events' + + value 'REOPEN', 'Reopens the work item.', value: 'reopen' + value 'CLOSE', 'Closes the work item.', value: 'close' + end + end +end |