diff options
Diffstat (limited to 'app/graphql')
111 files changed, 1507 insertions, 640 deletions
diff --git a/app/graphql/mutations/alert_management/alerts/set_assignees.rb b/app/graphql/mutations/alert_management/alerts/set_assignees.rb index 500e2b868b1..a8513417c1c 100644 --- a/app/graphql/mutations/alert_management/alerts/set_assignees.rb +++ b/app/graphql/mutations/alert_management/alerts/set_assignees.rb @@ -7,14 +7,14 @@ module Mutations graphql_name 'AlertSetAssignees' argument :assignee_usernames, - [GraphQL::Types::String], - required: true, - description: 'Usernames to assign to the alert. Replaces existing assignees by default.' + [GraphQL::Types::String], + required: true, + description: 'Usernames to assign to the alert. Replaces existing assignees by default.' argument :operation_mode, - Types::MutationOperationModeEnum, - required: false, - description: 'Operation to perform. Defaults to REPLACE.' + Types::MutationOperationModeEnum, + required: false, + description: 'Operation to perform. Defaults to REPLACE.' def resolve(args) alert = authorized_find!(project_path: args[:project_path], iid: args[:iid]) diff --git a/app/graphql/mutations/alert_management/base.rb b/app/graphql/mutations/alert_management/base.rb index 771ace5510f..615c0f43a15 100644 --- a/app/graphql/mutations/alert_management/base.rb +++ b/app/graphql/mutations/alert_management/base.rb @@ -6,27 +6,27 @@ module Mutations include Gitlab::Utils::UsageData argument :project_path, GraphQL::Types::ID, - required: true, - description: "Project the alert to mutate is in." + required: true, + description: "Project the alert to mutate is in." argument :iid, GraphQL::Types::String, - required: true, - description: "IID of the alert to mutate." + required: true, + description: "IID of the alert to mutate." field :alert, - Types::AlertManagement::AlertType, - null: true, - description: "Alert after mutation." + Types::AlertManagement::AlertType, + null: true, + description: "Alert after mutation." field :todo, - Types::TodoType, - null: true, - description: "To-do item after mutation." + Types::TodoType, + null: true, + description: "To-do item after mutation." field :issue, - Types::IssueType, - null: true, - description: "Issue created after mutation." + Types::IssueType, + null: true, + description: "Issue created after mutation." authorize :update_alert_management_alert diff --git a/app/graphql/mutations/alert_management/http_integration/create.rb b/app/graphql/mutations/alert_management/http_integration/create.rb index f8d1a383706..fccef8cd3ad 100644 --- a/app/graphql/mutations/alert_management/http_integration/create.rb +++ b/app/graphql/mutations/alert_management/http_integration/create.rb @@ -9,16 +9,16 @@ module Mutations include FindsProject argument :project_path, GraphQL::Types::ID, - required: true, - description: 'Project to create the integration in.' + required: true, + description: 'Project to create the integration in.' argument :name, GraphQL::Types::String, - required: true, - description: 'Name of the integration.' + required: true, + description: 'Name of the integration.' argument :active, GraphQL::Types::Boolean, - required: true, - description: 'Whether the integration is receiving alerts.' + required: true, + description: 'Whether the integration is receiving alerts.' def resolve(args) project = authorized_find!(args[:project_path]) diff --git a/app/graphql/mutations/alert_management/http_integration/destroy.rb b/app/graphql/mutations/alert_management/http_integration/destroy.rb index dc5c73ecff6..9da50a4c4ce 100644 --- a/app/graphql/mutations/alert_management/http_integration/destroy.rb +++ b/app/graphql/mutations/alert_management/http_integration/destroy.rb @@ -7,8 +7,8 @@ module Mutations graphql_name 'HttpIntegrationDestroy' argument :id, Types::GlobalIDType[::AlertManagement::HttpIntegration], - required: true, - description: "ID of the integration to remove." + required: true, + description: "ID of the integration to remove." def resolve(id:) integration = authorized_find!(id: id) diff --git a/app/graphql/mutations/alert_management/http_integration/http_integration_base.rb b/app/graphql/mutations/alert_management/http_integration/http_integration_base.rb index 2f25d315d2e..9434ac1637e 100644 --- a/app/graphql/mutations/alert_management/http_integration/http_integration_base.rb +++ b/app/graphql/mutations/alert_management/http_integration/http_integration_base.rb @@ -5,9 +5,9 @@ module Mutations module HttpIntegration class HttpIntegrationBase < BaseMutation field :integration, - Types::AlertManagement::HttpIntegrationType, - null: true, - description: "HTTP integration." + Types::AlertManagement::HttpIntegrationType, + null: true, + description: "HTTP integration." authorize :admin_operations diff --git a/app/graphql/mutations/alert_management/http_integration/reset_token.rb b/app/graphql/mutations/alert_management/http_integration/reset_token.rb index 83ad7762408..bed3cf08674 100644 --- a/app/graphql/mutations/alert_management/http_integration/reset_token.rb +++ b/app/graphql/mutations/alert_management/http_integration/reset_token.rb @@ -7,8 +7,8 @@ module Mutations graphql_name 'HttpIntegrationResetToken' argument :id, Types::GlobalIDType[::AlertManagement::HttpIntegration], - required: true, - description: "ID of the integration to mutate." + required: true, + description: "ID of the integration to mutate." def resolve(id:) integration = authorized_find!(id: id) diff --git a/app/graphql/mutations/alert_management/http_integration/update.rb b/app/graphql/mutations/alert_management/http_integration/update.rb index 78424e317b8..06d0b7163b0 100644 --- a/app/graphql/mutations/alert_management/http_integration/update.rb +++ b/app/graphql/mutations/alert_management/http_integration/update.rb @@ -7,16 +7,16 @@ module Mutations graphql_name 'HttpIntegrationUpdate' argument :id, Types::GlobalIDType[::AlertManagement::HttpIntegration], - required: true, - description: "ID of the integration to mutate." + required: true, + description: "ID of the integration to mutate." argument :name, GraphQL::Types::String, - required: false, - description: "Name of the integration." + required: false, + description: "Name of the integration." argument :active, GraphQL::Types::Boolean, - required: false, - description: "Whether the integration is receiving alerts." + required: false, + description: "Whether the integration is receiving alerts." def resolve(args) integration = authorized_find!(id: args[:id]) diff --git a/app/graphql/mutations/alert_management/prometheus_integration/create.rb b/app/graphql/mutations/alert_management/prometheus_integration/create.rb index b06a4f58df5..665ce96f0f9 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/create.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/create.rb @@ -9,16 +9,16 @@ module Mutations include FindsProject argument :project_path, GraphQL::Types::ID, - required: true, - description: 'Project to create the integration in.' + required: true, + description: 'Project to create the integration in.' argument :active, GraphQL::Types::Boolean, - required: true, - description: 'Whether the integration is receiving alerts.' + required: true, + description: 'Whether the integration is receiving alerts.' argument :api_url, GraphQL::Types::String, - required: false, - description: 'Endpoint at which Prometheus can be queried.' + required: false, + description: 'Endpoint at which Prometheus can be queried.' def resolve(args) project = authorized_find!(args[:project_path]) diff --git a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb index 29834d63f35..28729ec70cd 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb @@ -5,9 +5,9 @@ module Mutations module PrometheusIntegration class PrometheusIntegrationBase < BaseMutation field :integration, - Types::AlertManagement::PrometheusIntegrationType, - null: true, - description: "Newly created integration." + Types::AlertManagement::PrometheusIntegrationType, + null: true, + description: "Newly created integration." authorize :admin_project diff --git a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb index 71c02efdc03..15e6763b1ee 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb @@ -7,8 +7,8 @@ module Mutations graphql_name 'PrometheusIntegrationResetToken' argument :id, Types::GlobalIDType[::Integrations::Prometheus], - required: true, - description: "ID of the integration to mutate." + required: true, + description: "ID of the integration to mutate." def resolve(id:) integration = authorized_find!(id: id) diff --git a/app/graphql/mutations/alert_management/prometheus_integration/update.rb b/app/graphql/mutations/alert_management/prometheus_integration/update.rb index 50aafdc26a6..593624aaafd 100644 --- a/app/graphql/mutations/alert_management/prometheus_integration/update.rb +++ b/app/graphql/mutations/alert_management/prometheus_integration/update.rb @@ -7,16 +7,16 @@ module Mutations graphql_name 'PrometheusIntegrationUpdate' argument :id, Types::GlobalIDType[::Integrations::Prometheus], - required: true, - description: "ID of the integration to mutate." + required: true, + description: "ID of the integration to mutate." argument :active, GraphQL::Types::Boolean, - required: false, - description: "Whether the integration is receiving alerts." + required: false, + description: "Whether the integration is receiving alerts." argument :api_url, GraphQL::Types::String, - required: false, - description: "Endpoint at which Prometheus can be queried." + required: false, + description: "Endpoint at which Prometheus can be queried." def resolve(args) integration = authorized_find!(id: args[:id]) diff --git a/app/graphql/mutations/alert_management/update_alert_status.rb b/app/graphql/mutations/alert_management/update_alert_status.rb index be271a7d795..a0d06ebf221 100644 --- a/app/graphql/mutations/alert_management/update_alert_status.rb +++ b/app/graphql/mutations/alert_management/update_alert_status.rb @@ -6,8 +6,8 @@ module Mutations graphql_name 'UpdateAlertStatus' argument :status, Types::AlertManagement::StatusEnum, - required: true, - description: 'Status to set the alert.' + required: true, + description: 'Status to set the alert.' def resolve(project_path:, iid:, status:) alert = authorized_find!(project_path: project_path, iid: iid) diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb index 65065de0de4..0223c978cf9 100644 --- a/app/graphql/mutations/award_emojis/base.rb +++ b/app/graphql/mutations/award_emojis/base.rb @@ -3,7 +3,7 @@ module Mutations module AwardEmojis class Base < BaseMutation - NOT_EMOJI_AWARDABLE = 'You cannot award emoji to this resource.' + NOT_EMOJI_AWARDABLE = 'You cannot add emoji reactions to this resource.' authorize :award_emoji @@ -20,7 +20,7 @@ module Mutations field :award_emoji, Types::AwardEmojis::AwardEmojiType, null: true, - description: 'Award emoji after mutation.' + description: 'Emoji reactions after mutation.' private diff --git a/app/graphql/mutations/ci/pipeline_schedule/create.rb b/app/graphql/mutations/ci/pipeline_schedule/create.rb index 71a366ed342..d21ac6fd727 100644 --- a/app/graphql/mutations/ci/pipeline_schedule/create.rb +++ b/app/graphql/mutations/ci/pipeline_schedule/create.rb @@ -51,28 +51,16 @@ module Mutations params = pipeline_schedule_attrs.merge(variables_attributes: variables.map(&:to_h)) - if ::Feature.enabled?(:ci_refactoring_pipeline_schedule_create_service, project) - response = ::Ci::PipelineSchedules::CreateService - .new(project, current_user, params) - .execute - - schedule = response.payload - - unless response.success? - return { - pipeline_schedule: nil, errors: response.errors - } - end - else - schedule = ::Ci::CreatePipelineScheduleService - .new(project, current_user, params) - .execute - - unless schedule.persisted? - return { - pipeline_schedule: nil, errors: schedule.errors.full_messages - } - end + response = ::Ci::PipelineSchedules::CreateService + .new(project, current_user, params) + .execute + + schedule = response.payload + + unless response.success? + return { + pipeline_schedule: nil, errors: response.errors + } end { diff --git a/app/graphql/mutations/ci/pipeline_trigger/base.rb b/app/graphql/mutations/ci/pipeline_trigger/base.rb new file mode 100644 index 00000000000..23be70e7754 --- /dev/null +++ b/app/graphql/mutations/ci/pipeline_trigger/base.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module PipelineTrigger + class Base < BaseMutation + authorize :admin_build + authorize :admin_trigger + + PipelineTriggerID = ::Types::GlobalIDType[::Ci::Trigger] + + argument :id, PipelineTriggerID, + required: true, + description: 'ID of the pipeline trigger token to mutate.' + end + end + end +end diff --git a/app/graphql/mutations/ci/pipeline_trigger/create.rb b/app/graphql/mutations/ci/pipeline_trigger/create.rb new file mode 100644 index 00000000000..042f9b26dd0 --- /dev/null +++ b/app/graphql/mutations/ci/pipeline_trigger/create.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module PipelineTrigger + class Create < BaseMutation + graphql_name 'PipelineTriggerCreate' + + include FindsProject + + authorize :admin_build + + argument :project_path, GraphQL::Types::ID, + required: true, + description: 'Full path of the project that the pipeline trigger token to mutate is in.' + + argument :description, GraphQL::Types::String, + required: true, + description: 'Description of the pipeline trigger token.' + + field :pipeline_trigger, Types::Ci::PipelineTriggerType, + null: true, + description: 'Mutated pipeline trigger token.' + + def resolve(project_path:, description:) + project = authorized_find!(project_path) + + trigger = project.triggers.create(owner: current_user, description: description) + + { + pipeline_trigger: trigger, + errors: trigger.errors.full_messages + } + end + end + end + end +end diff --git a/app/graphql/mutations/ci/pipeline_trigger/delete.rb b/app/graphql/mutations/ci/pipeline_trigger/delete.rb new file mode 100644 index 00000000000..bc18f58ec43 --- /dev/null +++ b/app/graphql/mutations/ci/pipeline_trigger/delete.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module PipelineTrigger + class Delete < Base + graphql_name 'PipelineTriggerDelete' + + def resolve(id:) + trigger = authorized_find!(id: id) + + errors = trigger.destroy ? [] : ['Could not remove the trigger'] + + { errors: errors } + end + end + end + end +end diff --git a/app/graphql/mutations/ci/pipeline_trigger/update.rb b/app/graphql/mutations/ci/pipeline_trigger/update.rb new file mode 100644 index 00000000000..fa68593eb09 --- /dev/null +++ b/app/graphql/mutations/ci/pipeline_trigger/update.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module PipelineTrigger + class Update < Base + graphql_name 'PipelineTriggerUpdate' + + argument :description, GraphQL::Types::String, + required: true, + description: 'Description of the pipeline trigger token.' + + field :pipeline_trigger, Types::Ci::PipelineTriggerType, + null: true, + description: 'Mutated pipeline trigger token.' + + def resolve(id:, description:) + trigger = authorized_find!(id: id) + + trigger.description = description + + trigger.save + + { + pipeline_trigger: trigger, + errors: trigger.errors.full_messages + } + end + end + end + end +end diff --git a/app/graphql/mutations/concerns/mutations/validate_time_estimate.rb b/app/graphql/mutations/concerns/mutations/validate_time_estimate.rb new file mode 100644 index 00000000000..82a56fd04f3 --- /dev/null +++ b/app/graphql/mutations/concerns/mutations/validate_time_estimate.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Mutations + module ValidateTimeEstimate + private + + def validate_time_estimate(time_estimate) + return unless time_estimate + + parsed_time_estimate = Gitlab::TimeTrackingFormatter.parse(time_estimate, keep_zero: true) + + if parsed_time_estimate.nil? + raise Gitlab::Graphql::Errors::ArgumentError, + 'timeEstimate must be formatted correctly, for example `1h 30m`' + elsif parsed_time_estimate < 0 + raise Gitlab::Graphql::Errors::ArgumentError, + 'timeEstimate must be greater than or equal to zero. ' \ + 'Remember that every new timeEstimate overwrites the previous value.' + end + end + end +end diff --git a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb index f009abdba70..7aa78509bea 100644 --- a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb +++ b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb @@ -47,7 +47,7 @@ module Mutations argument :award_emoji_widget, ::Types::WorkItems::Widgets::AwardEmojiUpdateInputType, required: false, - description: 'Input for award emoji widget.' + description: 'Input for emoji reactions widget.' end end end diff --git a/app/graphql/mutations/environments/create.rb b/app/graphql/mutations/environments/create.rb index f18ce0eba97..76a5bf2f551 100644 --- a/app/graphql/mutations/environments/create.rb +++ b/app/graphql/mutations/environments/create.rb @@ -40,6 +40,11 @@ module Mutations required: false, description: 'Kubernetes namespace of the environment.' + argument :flux_resource_path, + GraphQL::Types::String, + required: false, + description: 'Flux resource path of the environment.' + field :environment, Types::EnvironmentType, null: true, diff --git a/app/graphql/mutations/environments/update.rb b/app/graphql/mutations/environments/update.rb index 07ab22685cc..44b9398c233 100644 --- a/app/graphql/mutations/environments/update.rb +++ b/app/graphql/mutations/environments/update.rb @@ -33,6 +33,11 @@ module Mutations required: false, description: 'Kubernetes namespace of the environment.' + argument :flux_resource_path, + GraphQL::Types::String, + required: false, + description: 'Flux resource path of the environment.' + field :environment, Types::EnvironmentType, null: true, diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb index 2a863893cf1..35deb9e0af8 100644 --- a/app/graphql/mutations/issues/update.rb +++ b/app/graphql/mutations/issues/update.rb @@ -6,6 +6,7 @@ module Mutations graphql_name 'UpdateIssue' include CommonMutationArguments + include ValidateTimeEstimate argument :title, GraphQL::Types::String, required: false, @@ -54,9 +55,7 @@ module Mutations raise Gitlab::Graphql::Errors::ArgumentError, 'labelIds is mutually exclusive with any of addLabelIds or removeLabelIds' end - if !time_estimate.nil? && Gitlab::TimeTrackingFormatter.parse(time_estimate, keep_zero: true).nil? - raise Gitlab::Graphql::Errors::ArgumentError, 'timeEstimate must be formatted correctly, for example `1h 30m`' - end + validate_time_estimate(time_estimate) super end diff --git a/app/graphql/mutations/merge_requests/update.rb b/app/graphql/mutations/merge_requests/update.rb index da4db7342a3..470292df86c 100644 --- a/app/graphql/mutations/merge_requests/update.rb +++ b/app/graphql/mutations/merge_requests/update.rb @@ -5,6 +5,8 @@ module Mutations class Update < Base graphql_name 'MergeRequestUpdate' + include ValidateTimeEstimate + description 'Update attributes of a merge request' argument :title, GraphQL::Types::String, @@ -45,10 +47,7 @@ module Mutations end def ready?(time_estimate: nil, **args) - if !time_estimate.nil? && Gitlab::TimeTrackingFormatter.parse(time_estimate, keep_zero: true).nil? - raise Gitlab::Graphql::Errors::ArgumentError, - 'timeEstimate must be formatted correctly, for example `1h 30m`' - end + validate_time_estimate(time_estimate) super end diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb index 296efa19bb7..59ddffe3aad 100644 --- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb +++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb @@ -61,14 +61,10 @@ module Mutations end end - def resolve(args) - annotation_response = ::Metrics::Dashboard::Annotations::CreateService.new(context[:current_user], annotation_create_params(args)).execute - - annotation = annotation_response[:annotation] - + def resolve(_args) { - annotation: annotation.valid? ? annotation : nil, - errors: errors_on_object(annotation) + annotation: nil, + errors: [] } end diff --git a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb index 32047cda213..61fcf8e0b13 100644 --- a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb +++ b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb @@ -13,19 +13,11 @@ module Mutations required: true, description: 'Global ID of the annotation to delete.' + # rubocop:disable Lint/UnusedMethodArgument def resolve(id:) - raise_resource_not_available_error! if Feature.enabled?(:remove_monitor_metrics) - - annotation = authorized_find!(id: id) - - result = ::Metrics::Dashboard::Annotations::DeleteService.new(context[:current_user], annotation).execute - - errors = Array.wrap(result[:message]) - - { - errors: errors - } + raise_resource_not_available_error! end + # rubocop:enable Lint/UnusedMethodArgument end end end diff --git a/app/graphql/mutations/namespace/package_settings/update.rb b/app/graphql/mutations/namespace/package_settings/update.rb index 96bee693a1e..4e71bed52c6 100644 --- a/app/graphql/mutations/namespace/package_settings/update.rb +++ b/app/graphql/mutations/namespace/package_settings/update.rb @@ -8,6 +8,8 @@ module Mutations include Mutations::ResolvesNamespace + NUGET_DUPLICATES_FF_ERROR = '`nuget_duplicates_option` feature flag is disabled.' + description <<~DESC These settings can be adjusted by the group Owner or Maintainer. [Issue 370471](https://gitlab.com/gitlab-org/gitlab/-/issues/370471) proposes limiting @@ -41,6 +43,16 @@ module Mutations required: false, description: copy_field_description(Types::Namespace::PackageSettingsType, :generic_duplicate_exception_regex) + argument :nuget_duplicates_allowed, + GraphQL::Types::Boolean, + required: false, + description: copy_field_description(Types::Namespace::PackageSettingsType, :nuget_duplicates_allowed) + + argument :nuget_duplicate_exception_regex, + Types::UntrustedRegexp, + required: false, + description: copy_field_description(Types::Namespace::PackageSettingsType, :nuget_duplicate_exception_regex) + argument :maven_package_requests_forwarding, GraphQL::Types::Boolean, required: false, @@ -79,6 +91,10 @@ module Mutations def resolve(namespace_path:, **args) namespace = authorized_find!(namespace_path: namespace_path) + if nuget_duplicate_settings_present?(args) && Feature.disabled?(:nuget_duplicates_option, namespace) + raise_resource_not_available_error! NUGET_DUPLICATES_FF_ERROR + end + result = ::Namespaces::PackageSettings::UpdateService .new(container: namespace, current_user: current_user, params: args) .execute @@ -94,6 +110,10 @@ module Mutations def find_object(namespace_path:) resolve_namespace(full_path: namespace_path) end + + def nuget_duplicate_settings_present?(args) + args.key?(:nuget_duplicates_allowed) || args.key?(:nuget_duplicate_exception_regex) + end end end end diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb index 9f7b7b5db97..7ce508e5ef1 100644 --- a/app/graphql/mutations/work_items/create.rb +++ b/app/graphql/mutations/work_items/create.rb @@ -14,6 +14,7 @@ module Mutations authorize :create_work_item MUTUALLY_EXCLUSIVE_ARGUMENTS_ERROR = 'Please provide either projectPath or namespacePath argument, but not both.' + DISABLED_FF_ERROR = 'namespace_level_work_items feature flag is disabled. Only project paths allowed.' argument :confidential, GraphQL::Types::Boolean, required: false, @@ -59,6 +60,7 @@ module Mutations def resolve(project_path: nil, namespace_path: nil, **attributes) container_path = project_path || namespace_path container = authorized_find!(container_path) + check_feature_available!(container) params = global_id_compatibility_params(attributes).merge(author_id: current_user.id) type = ::WorkItems::Type.find(attributes[:work_item_type_id]) @@ -81,6 +83,12 @@ module Mutations private + def check_feature_available!(container) + return unless container.is_a?(::Group) && Feature.disabled?(:namespace_level_work_items, container) + + raise Gitlab::Graphql::Errors::ArgumentError, DISABLED_FF_ERROR + end + def global_id_compatibility_params(params) params[:work_item_type_id] = params[:work_item_type_id]&.model_id diff --git a/app/graphql/mutations/work_items/linked_items/add.rb b/app/graphql/mutations/work_items/linked_items/add.rb new file mode 100644 index 00000000000..b346b074e85 --- /dev/null +++ b/app/graphql/mutations/work_items/linked_items/add.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + module LinkedItems + class Add < Base + graphql_name 'WorkItemAddLinkedItems' + description 'Add linked items to the work item.' + + argument :link_type, ::Types::WorkItems::RelatedLinkTypeEnum, + required: false, description: 'Type of link. Defaults to `RELATED`.' + + private + + def update_links(work_item, params) + Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/419555') + + gids = params.delete(:work_items_ids) + work_items = begin + GitlabSchema.parse_gids(gids, expected_type: ::WorkItem).map(&:find) + rescue ActiveRecord::RecordNotFound => e + raise Gitlab::Graphql::Errors::ArgumentError, e + end + + ::WorkItems::RelatedWorkItemLinks::CreateService + .new(work_item, current_user, { target_issuable: work_items, link_type: params[:link_type] }) + .execute + end + end + end + end +end diff --git a/app/graphql/mutations/work_items/linked_items/base.rb b/app/graphql/mutations/work_items/linked_items/base.rb new file mode 100644 index 00000000000..1d8d74b02ac --- /dev/null +++ b/app/graphql/mutations/work_items/linked_items/base.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + module LinkedItems + class Base < BaseMutation + # Limit maximum number of items that can be linked at a time to avoid overloading the DB + # See https://gitlab.com/gitlab-org/gitlab/-/issues/419555 + MAX_WORK_ITEMS = 3 + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, description: 'Global ID of the work item.' + argument :work_items_ids, [::Types::GlobalIDType[::WorkItem]], + required: true, + description: "Global IDs of the items to link. Maximum number of IDs you can provide: #{MAX_WORK_ITEMS}." + + field :work_item, Types::WorkItemType, + null: true, description: 'Updated work item.' + + field :message, GraphQL::Types::String, + null: true, description: 'Linked items update result message.' + + authorize :read_work_item + + def ready?(**args) + if args[:work_items_ids].size > MAX_WORK_ITEMS + raise Gitlab::Graphql::Errors::ArgumentError, + format( + _('No more than %{max_work_items} work items can be linked at the same time.'), + max_work_items: MAX_WORK_ITEMS + ) + end + + super + end + + def resolve(**args) + work_item = authorized_find!(id: args.delete(:id)) + raise_resource_not_available_error! unless work_item.project.linked_work_items_feature_flag_enabled? + + service_response = update_links(work_item, args) + + { + work_item: work_item, + errors: service_response[:status] == :error ? Array.wrap(service_response[:message]) : [], + message: service_response[:status] == :success ? service_response[:message] : '' + } + end + + private + + def update_links(work_item, params) + raise NotImplementedError + end + end + end + end +end diff --git a/app/graphql/mutations/work_items/subscribe.rb b/app/graphql/mutations/work_items/subscribe.rb new file mode 100644 index 00000000000..a29c3416c3d --- /dev/null +++ b/app/graphql/mutations/work_items/subscribe.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class Subscribe < BaseMutation + graphql_name 'WorkItemSubscribe' + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, + description: 'Global ID of the work item.' + + argument :subscribed, + GraphQL::Types::Boolean, + required: true, + description: 'Desired state of the subscription.' + + field :work_item, Types::WorkItemType, + null: true, + description: 'Work item after mutation.' + + authorize :update_subscription + + def resolve(args) + work_item = authorized_find!(id: args[:id]) + + update_subscription(work_item, args[:subscribed]) + + { + work_item: work_item, + errors: [] + } + end + + private + + def update_subscription(work_item, subscribed_state) + work_item.set_subscription(current_user, subscribed_state, work_item.project) + end + end + end +end diff --git a/app/graphql/queries/repository/blob_info.query.graphql b/app/graphql/queries/repository/blob_info.query.graphql index fd463436ed4..7419961a564 100644 --- a/app/graphql/queries/repository/blob_info.query.graphql +++ b/app/graphql/queries/repository/blob_info.query.graphql @@ -2,6 +2,7 @@ query getBlobInfo( $projectPath: ID! $filePath: String! $ref: String! + $refType: RefType $shouldFetchRawText: Boolean! ) { project(fullPath: $projectPath) { @@ -10,7 +11,7 @@ query getBlobInfo( repository { __typename empty - blobs(paths: [$filePath], ref: $ref) { + blobs(paths: [$filePath], ref: $ref, refType: $refType) { __typename nodes { __typename diff --git a/app/graphql/queries/repository/files.query.graphql b/app/graphql/queries/repository/files.query.graphql index a83880ce696..bd7bb8ba787 100644 --- a/app/graphql/queries/repository/files.query.graphql +++ b/app/graphql/queries/repository/files.query.graphql @@ -19,6 +19,7 @@ query getFiles( $projectPath: ID! $path: String $ref: String! + $refType: RefType $pageSize: Int! $nextPageCursor: String ) { @@ -27,7 +28,7 @@ query getFiles( __typename repository { __typename - tree(path: $path, ref: $ref) { + tree(path: $path, ref: $ref, refType: $refType) { __typename trees(first: $pageSize, after: $nextPageCursor) { __typename diff --git a/app/graphql/queries/repository/paginated_tree.query.graphql b/app/graphql/queries/repository/paginated_tree.query.graphql index e82bc6d0734..68aa90046b9 100644 --- a/app/graphql/queries/repository/paginated_tree.query.graphql +++ b/app/graphql/queries/repository/paginated_tree.query.graphql @@ -7,13 +7,19 @@ fragment TreeEntry on Entry { type } -query getPaginatedTree($projectPath: ID!, $path: String, $ref: String!, $nextPageCursor: String) { +query getPaginatedTree( + $projectPath: ID! + $path: String + $ref: String! + $nextPageCursor: String + $refType: RefType +) { project(fullPath: $projectPath) { id __typename repository { __typename - paginatedTree(path: $path, ref: $ref, after: $nextPageCursor) { + paginatedTree(path: $path, ref: $ref, refType: $refType, after: $nextPageCursor) { __typename pageInfo { __typename diff --git a/app/graphql/queries/repository/path_last_commit.query.graphql b/app/graphql/queries/repository/path_last_commit.query.graphql index facbf1555fc..738fdf534cb 100644 --- a/app/graphql/queries/repository/path_last_commit.query.graphql +++ b/app/graphql/queries/repository/path_last_commit.query.graphql @@ -1,10 +1,10 @@ -query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { +query pathLastCommit($projectPath: ID!, $path: String, $ref: String!, $refType: RefType) { project(fullPath: $projectPath) { __typename id repository { __typename - paginatedTree(path: $path, ref: $ref) { + paginatedTree(path: $path, ref: $ref, refType: $refType) { __typename nodes { __typename diff --git a/app/graphql/resolvers/abuse_report_labels_resolver.rb b/app/graphql/resolvers/abuse_report_labels_resolver.rb new file mode 100644 index 00000000000..86cebe8e541 --- /dev/null +++ b/app/graphql/resolvers/abuse_report_labels_resolver.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Resolvers + class AbuseReportLabelsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorize :read_label + + type Types::LabelType.connection_type, null: true + + argument :search_term, GraphQL::Types::String, + required: false, + description: 'Search term to find labels with.' + + def resolve(**args) + ::Admin::AbuseReportLabelsFinder.new(context[:current_user], args).execute + end + end +end diff --git a/app/graphql/resolvers/abuse_report_resolver.rb b/app/graphql/resolvers/abuse_report_resolver.rb new file mode 100644 index 00000000000..770409601b9 --- /dev/null +++ b/app/graphql/resolvers/abuse_report_resolver.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Resolvers + class AbuseReportResolver < BaseResolver + description 'Retrieve an abuse report' + + type Types::AbuseReportType, null: true + + argument :id, Types::GlobalIDType[AbuseReport], required: true, description: 'ID of the abuse report.' + + def resolve(id:) + ::AbuseReport.find_by_id(extract_abuse_report_id(id)) + end + + private + + def extract_abuse_report_id(gid) + GitlabSchema.parse_gid(gid, expected_type: ::AbuseReport).model_id + end + end +end diff --git a/app/graphql/resolvers/autocomplete_users_resolver.rb b/app/graphql/resolvers/autocomplete_users_resolver.rb new file mode 100644 index 00000000000..40c53a46311 --- /dev/null +++ b/app/graphql/resolvers/autocomplete_users_resolver.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Resolvers + class AutocompleteUsersResolver < BaseResolver + type [::Types::Users::AutocompletedUserType], null: true + + argument :search, GraphQL::Types::String, + required: false, + description: 'Query to search users by name, username, or public email.' + + def resolve(search: nil) + ::Autocomplete::UsersFinder.new( + current_user: context[:current_user], + project: project, + group: group, + params: { + search: search + } + ).execute + end + + private + + def project + object if object.is_a?(Project) + end + + def group + object if object.is_a?(Group) + end + end +end diff --git a/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb b/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb new file mode 100644 index 00000000000..3d6e3b3e75d --- /dev/null +++ b/app/graphql/resolvers/ci/pipeline_triggers_resolver.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Resolvers + module Ci + class PipelineTriggersResolver < BaseResolver + include LooksAhead + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorize :admin_build + type Types::Ci::PipelineTriggerType.connection_type, null: false + + def resolve_with_lookahead + apply_lookahead(object.triggers) + end + + private + + def unconditional_includes + [:trigger_requests] + end + end + end +end diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb index c0a068097a7..e9e7ea9f77f 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -59,7 +59,8 @@ module ResolvesMergeRequests timelogs: [:timelogs], pipelines: [:merge_request_diffs], # used by `recent_diff_head_shas` to load pipelines committers: [merge_request_diff: [:merge_request_diff_commits]], - suggested_reviewers: [:predictions] + suggested_reviewers: [:predictions], + diff_stats: [latest_merge_request_diff: [:merge_request_diff_commits]] } end end diff --git a/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb new file mode 100644 index 00000000000..92fb9ec5cef --- /dev/null +++ b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module WorkItems + module LookAheadPreloads + extend ActiveSupport::Concern + + prepended do + include ::LooksAhead + end + + private + + def preloads + { + work_item_type: :work_item_type, + web_url: { namespace: :route, project: [:project_namespace, { namespace: :route }] }, + widgets: { work_item_type: :enabled_widget_definitions } + } + end + + def nested_preloads + { + widgets: widget_preloads, + user_permissions: { update_work_item: :assignees }, + project: { jira_import_status: { project: :jira_imports } }, + author: { + location: { author: :user_detail }, + gitpod_enabled: { author: :user_preference } + } + } + end + + def widget_preloads + { + last_edited_by: :last_edited_by, + assignees: :assignees, + parent: :work_item_parent, + children: { work_item_children_by_relative_position: [:author, { project: :project_feature }] }, + labels: :labels, + milestone: { milestone: [:project, :group] }, + subscribed: [:assignees, :award_emoji, { notes: [:author, :award_emoji] }], + award_emoji: { award_emoji: :awardable } + } + end + + def unconditional_includes + [ + { + project: [:project_feature, :group] + }, + :author + ] + end + end +end + +WorkItems::LookAheadPreloads.prepend_mod diff --git a/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb b/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb index aad9bbebafb..b967460c7ff 100644 --- a/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb +++ b/app/graphql/resolvers/metrics/dashboards/annotation_resolver.rb @@ -16,11 +16,10 @@ module Resolvers alias_method :dashboard, :object - def resolve(**args) + def resolve(**_args) return if Feature.enabled?(:remove_monitor_metrics) - return [] unless dashboard - ::Metrics::Dashboards::AnnotationsFinder.new(dashboard: dashboard, params: args).execute + [] end end end diff --git a/app/graphql/resolvers/namespaces/work_items_resolver.rb b/app/graphql/resolvers/namespaces/work_items_resolver.rb new file mode 100644 index 00000000000..54bb8392071 --- /dev/null +++ b/app/graphql/resolvers/namespaces/work_items_resolver.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Resolvers + module Namespaces + class WorkItemsResolver < BaseResolver + prepend ::WorkItems::LookAheadPreloads + + type Types::WorkItemType.connection_type, null: true + + def resolve_with_lookahead(**args) + return unless Feature.enabled?(:namespace_level_work_items, resource_parent) + return WorkItem.none if resource_parent.nil? + + finder = ::WorkItems::NamespaceWorkItemsFinder.new(current_user, args.merge( + namespace_id: resource_parent + )) + + Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all do |q| + apply_lookahead(q) + end + end + + private + + def resource_parent + # The project could have been loaded in batch by `BatchLoader`. + # At this point we need the `id` of the project to query for work items, so + # make sure it's loaded and not `nil` before continuing. + object.respond_to?(:sync) ? object.sync : object + end + strong_memoize_attr :resource_parent + end + end +end diff --git a/app/graphql/resolvers/work_items/linked_items_resolver.rb b/app/graphql/resolvers/work_items/linked_items_resolver.rb new file mode 100644 index 00000000000..9c71cd7c0c9 --- /dev/null +++ b/app/graphql/resolvers/work_items/linked_items_resolver.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Resolvers + module WorkItems + class LinkedItemsResolver < BaseResolver + alias_method :linked_items_widget, :object + + type Types::WorkItems::LinkedItemType.connection_type, null: true + + def resolve + related_work_items.map do |related_work_item| + { + link_id: related_work_item.issue_link_id, + link_type: related_work_item.issue_link_type, + link_created_at: related_work_item.issue_link_created_at, + link_updated_at: related_work_item.issue_link_updated_at, + work_item: related_work_item + } + end + end + + private + + def related_work_items + return [] unless work_item.project.linked_work_items_feature_flag_enabled? + + work_item.related_issues(current_user, preload: { project: [:project_feature, :group] }) + end + + def work_item + linked_items_widget.work_item + end + strong_memoize_attr :work_item + end + end +end diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb index 14eec4f696a..d4f73361e05 100644 --- a/app/graphql/resolvers/work_items_resolver.rb +++ b/app/graphql/resolvers/work_items_resolver.rb @@ -2,8 +2,8 @@ module Resolvers class WorkItemsResolver < BaseResolver + prepend ::WorkItems::LookAheadPreloads include SearchArguments - include LooksAhead include ::WorkItems::SharedFilterArguments argument :iid, @@ -28,48 +28,6 @@ module Resolvers private - def preloads - { - work_item_type: :work_item_type, - web_url: { namespace: :route, project: [:project_namespace, { namespace: :route }] }, - widgets: { work_item_type: :enabled_widget_definitions } - } - end - - def nested_preloads - { - widgets: widget_preloads, - user_permissions: { update_work_item: :assignees }, - project: { jira_import_status: { project: :jira_imports } }, - author: { - location: { author: :user_detail }, - gitpod_enabled: { author: :user_preference } - } - } - end - - def widget_preloads - { - last_edited_by: :last_edited_by, - assignees: :assignees, - parent: :work_item_parent, - children: { work_item_children_by_relative_position: [:author, { project: :project_feature }] }, - labels: :labels, - milestone: { milestone: [:project, :group] }, - subscribed: [:assignees, :award_emoji, { notes: [:author, :award_emoji] }], - award_emoji: { award_emoji: :awardable } - } - end - - def unconditional_includes - [ - { - project: [:project_feature, :group] - }, - :author - ] - end - def prepare_finder_params(args) params = super(args) params[:iids] ||= [params.delete(:iid)].compact if params[:iid] @@ -88,4 +46,4 @@ module Resolvers end end -Resolvers::WorkItemsResolver.prepend_mod_with('Resolvers::WorkItemsResolver') +Resolvers::WorkItemsResolver.prepend_mod diff --git a/app/graphql/types/abuse_report_type.rb b/app/graphql/types/abuse_report_type.rb new file mode 100644 index 00000000000..012e709cdb5 --- /dev/null +++ b/app/graphql/types/abuse_report_type.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class AbuseReportType < BaseObject + graphql_name 'AbuseReport' + description 'An abuse report' + authorize :read_abuse_report + + field :labels, ::Types::LabelType.connection_type, + null: true, description: 'Labels of the abuse report.' + end +end diff --git a/app/graphql/types/access_levels/deploy_key_type.rb b/app/graphql/types/access_levels/deploy_key_type.rb new file mode 100644 index 00000000000..e4e90619891 --- /dev/null +++ b/app/graphql/types/access_levels/deploy_key_type.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Types + module AccessLevels + class DeployKeyType < BaseObject + graphql_name 'AccessLevelDeployKey' + description 'Representation of a GitLab deploy key.' + + authorize :read_deploy_key + + field :id, + type: GraphQL::Types::ID, + null: false, + description: 'ID of the deploy key.' + + field :title, + type: GraphQL::Types::String, + null: false, + description: 'Title of the deploy key.' + + field :expires_at, + type: Types::DateType, + null: true, + description: 'Expiration date of the deploy key.' + + field :user, + type: Types::AccessLevels::UserType, + null: false, + description: 'User assigned to the deploy key.' + end + end +end diff --git a/app/graphql/types/access_levels/user_type.rb b/app/graphql/types/access_levels/user_type.rb new file mode 100644 index 00000000000..82aba673250 --- /dev/null +++ b/app/graphql/types/access_levels/user_type.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Types + module AccessLevels + class UserType < BaseObject + graphql_name 'AccessLevelUser' + description 'Representation of a GitLab user.' + + authorize :read_user + + present_using UserPresenter + + field :id, + type: GraphQL::Types::ID, + null: false, + description: 'ID of the user.' + + field :username, + type: GraphQL::Types::String, + null: false, + description: 'Username of the user.' + + field :name, + type: GraphQL::Types::String, + null: false, + resolver_method: :redacted_name, + description: <<~DESC + Human-readable name of the user. + Returns `****` if the user is a project bot and the requester does not have permission to view the project. + DESC + + field :public_email, + type: GraphQL::Types::String, + null: true, + description: "User's public email." + + field :avatar_url, + type: GraphQL::Types::String, + null: true, + description: "URL of the user's avatar." + + field :web_url, + type: GraphQL::Types::String, + null: false, + description: 'Web URL of the user.' + + field :web_path, + type: GraphQL::Types::String, + null: false, + description: 'Web path of the user.' + + def redacted_name + object.redacted_name(context[:current_user]) + end + + def avatar_url + object.avatar_url(only_path: false) + end + end + end +end diff --git a/app/graphql/types/achievements/achievement_type.rb b/app/graphql/types/achievements/achievement_type.rb index ec558981465..d733bf39a51 100644 --- a/app/graphql/types/achievements/achievement_type.rb +++ b/app/graphql/types/achievements/achievement_type.rb @@ -5,6 +5,8 @@ module Types class AchievementType < BaseObject graphql_name 'Achievement' + connection_type_class Types::CountableConnectionType + authorize :read_achievement field :id, diff --git a/app/graphql/types/achievements/user_achievement_type.rb b/app/graphql/types/achievements/user_achievement_type.rb index bf161d2f1e5..7cdcb66576c 100644 --- a/app/graphql/types/achievements/user_achievement_type.rb +++ b/app/graphql/types/achievements/user_achievement_type.rb @@ -5,6 +5,8 @@ module Types class UserAchievementType < BaseObject graphql_name 'UserAchievement' + connection_type_class Types::CountableConnectionType + authorize :read_user_achievement field :id, diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb index c17406b3e56..e85d0213613 100644 --- a/app/graphql/types/alert_management/alert_type.rb +++ b/app/graphql/types/alert_management/alert_type.rb @@ -8,8 +8,8 @@ module Types present_using ::AlertManagement::AlertPresenter - implements(Types::Notes::NoteableInterface) - implements(Types::TodoableInterface) + implements Types::Notes::NoteableInterface + implements Types::TodoableInterface authorize :read_alert_management_alert @@ -111,6 +111,12 @@ module Types null: true, description: 'Assignees of the alert.' + field :metrics_dashboard_url, + GraphQL::Types::String, + null: true, + description: 'URL for metrics embed for the alert.', + deprecated: { reason: 'Returns no data. Underlying feature was removed in 16.0', + milestone: '16.0' } field :runbook, GraphQL::Types::String, null: true, @@ -136,6 +142,10 @@ module Types method: :details_url, null: false, description: 'URL of the alert.' + + def metrics_dashboard_url + nil + end end end end diff --git a/app/graphql/types/alert_management/http_integration_type.rb b/app/graphql/types/alert_management/http_integration_type.rb index bba9cb1bbfc..7c026be86a3 100644 --- a/app/graphql/types/alert_management/http_integration_type.rb +++ b/app/graphql/types/alert_management/http_integration_type.rb @@ -6,7 +6,7 @@ module Types graphql_name 'AlertManagementHttpIntegration' description 'An endpoint and credentials used to accept alerts for a project' - implements(Types::AlertManagement::IntegrationType) + implements Types::AlertManagement::IntegrationType authorize :admin_operations diff --git a/app/graphql/types/alert_management/prometheus_integration_type.rb b/app/graphql/types/alert_management/prometheus_integration_type.rb index 9a2ef78eca7..0f61eeaa177 100644 --- a/app/graphql/types/alert_management/prometheus_integration_type.rb +++ b/app/graphql/types/alert_management/prometheus_integration_type.rb @@ -8,7 +8,7 @@ module Types include ::Gitlab::Routing - implements(Types::AlertManagement::IntegrationType) + implements Types::AlertManagement::IntegrationType authorize :admin_project diff --git a/app/graphql/types/branch_protections/push_access_level_type.rb b/app/graphql/types/branch_protections/push_access_level_type.rb index c5e21fad88d..2a66f1a4ec5 100644 --- a/app/graphql/types/branch_protections/push_access_level_type.rb +++ b/app/graphql/types/branch_protections/push_access_level_type.rb @@ -6,6 +6,11 @@ module Types graphql_name 'PushAccessLevel' description 'Defines which user roles, users, or groups can push to a protected branch.' accepts ::ProtectedBranch::PushAccessLevel + + field :deploy_key, + Types::AccessLevels::DeployKeyType, + null: true, + description: 'Deploy key assigned to the access level.' end end end diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb index f7ef94f58c0..45ecbf5c084 100644 --- a/app/graphql/types/ci/ci_cd_setting_type.rb +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -7,32 +7,37 @@ module Types authorize :admin_project - field :job_token_scope_enabled, - GraphQL::Types::Boolean, - null: true, - description: 'Indicates CI/CD job tokens generated in this project ' \ - 'have restricted access to other projects.', - method: :job_token_scope_enabled? - field :inbound_job_token_scope_enabled, - GraphQL::Types::Boolean, - null: true, - description: 'Indicates CI/CD job tokens generated in other projects ' \ - 'have restricted access to this project.', - method: :inbound_job_token_scope_enabled? - - field :keep_latest_artifact, GraphQL::Types::Boolean, null: true, - description: 'Whether to keep the latest builds artifacts.', - method: :keep_latest_artifacts_available? - field :merge_pipelines_enabled, GraphQL::Types::Boolean, null: true, - description: 'Whether merge pipelines are enabled.', - method: :merge_pipelines_enabled? - field :merge_trains_enabled, GraphQL::Types::Boolean, null: true, - description: 'Whether merge trains are enabled.', - method: :merge_trains_enabled? - - field :project, Types::ProjectType, null: true, - description: 'Project the CI/CD settings belong to.' + GraphQL::Types::Boolean, + null: true, + description: 'Indicates CI/CD job tokens generated in other projects ' \ + 'have restricted access to this project.', + method: :inbound_job_token_scope_enabled? + field :job_token_scope_enabled, + GraphQL::Types::Boolean, + null: true, + description: 'Indicates CI/CD job tokens generated in this project ' \ + 'have restricted access to other projects.', + method: :job_token_scope_enabled? + field :keep_latest_artifact, + GraphQL::Types::Boolean, + null: true, + description: 'Whether to keep the latest builds artifacts.', + method: :keep_latest_artifacts_available? + field :merge_pipelines_enabled, + GraphQL::Types::Boolean, + null: true, + description: 'Whether merge pipelines are enabled.', + method: :merge_pipelines_enabled? + field :merge_trains_enabled, + GraphQL::Types::Boolean, + null: true, + description: 'Whether merge trains are enabled.', + method: :merge_trains_enabled? + field :project, + Types::ProjectType, + null: true, + description: 'Project the CI/CD settings belong to.' end end end diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index 8bc50e974bb..e18770c2708 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -39,17 +39,15 @@ module Types end def action - if object.has_action? - { - button_title: object.action_button_title, - icon: object.action_icon, - method: object.action_method, - path: object.action_path, - title: object.action_title - } - else - nil - end + return unless object.has_action? + + { + button_title: object.action_button_title, + icon: object.action_icon, + method: object.action_method, + path: object.action_path, + title: object.action_title + } end end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/ci/group_environment_scope_type.rb b/app/graphql/types/ci/group_environment_scope_type.rb index 3a3a5a3f59f..0dd0ad963ac 100644 --- a/app/graphql/types/ci/group_environment_scope_type.rb +++ b/app/graphql/types/ci/group_environment_scope_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'CiGroupEnvironmentScope' description 'Ci/CD environment scope for a group.' - connection_type_class(Types::Ci::GroupEnvironmentScopeConnectionType) + connection_type_class Types::Ci::GroupEnvironmentScopeConnectionType field :name, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/ci/group_variable_type.rb b/app/graphql/types/ci/group_variable_type.rb index 7e2afba0d53..7be9b3df0b8 100644 --- a/app/graphql/types/ci/group_variable_type.rb +++ b/app/graphql/types/ci/group_variable_type.rb @@ -7,8 +7,8 @@ module Types graphql_name 'CiGroupVariable' description 'CI/CD variables for a group.' - connection_type_class(Types::Ci::GroupVariableConnectionType) - implements(VariableInterface) + connection_type_class Types::Ci::GroupVariableConnectionType + implements VariableInterface field :environment_scope, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/ci/instance_variable_type.rb b/app/graphql/types/ci/instance_variable_type.rb index 7ffc52deb73..e3230556769 100644 --- a/app/graphql/types/ci/instance_variable_type.rb +++ b/app/graphql/types/ci/instance_variable_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'CiInstanceVariable' description 'CI/CD variables for a GitLab instance.' - implements(VariableInterface) + implements VariableInterface field :id, GraphQL::Types::ID, null: false, diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 02b10f3e4bd..22eb32993c5 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -9,7 +9,7 @@ module Types present_using ::Ci::BuildPresenter - connection_type_class(Types::LimitedCountableConnectionType) + connection_type_class Types::LimitedCountableConnectionType expose_permissions Types::PermissionTypes::Ci::Job diff --git a/app/graphql/types/ci/manual_variable_type.rb b/app/graphql/types/ci/manual_variable_type.rb index ed92a6645b4..dcdaa3a6b19 100644 --- a/app/graphql/types/ci/manual_variable_type.rb +++ b/app/graphql/types/ci/manual_variable_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'CiManualVariable' description 'CI/CD variables given to a manual job.' - implements(VariableInterface) + implements VariableInterface field :environment_scope, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/ci/pipeline_schedule_type.rb b/app/graphql/types/ci/pipeline_schedule_type.rb index 904fa3f1c72..71a1f28ea38 100644 --- a/app/graphql/types/ci/pipeline_schedule_type.rb +++ b/app/graphql/types/ci/pipeline_schedule_type.rb @@ -7,7 +7,7 @@ module Types description 'Represents a pipeline schedule' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType expose_permissions Types::PermissionTypes::Ci::PipelineSchedules diff --git a/app/graphql/types/ci/pipeline_schedule_variable_type.rb b/app/graphql/types/ci/pipeline_schedule_variable_type.rb index 1cb407bc2e4..f9c18d6f7df 100644 --- a/app/graphql/types/ci/pipeline_schedule_variable_type.rb +++ b/app/graphql/types/ci/pipeline_schedule_variable_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_pipeline_schedule_variables - implements(VariableInterface) + implements VariableInterface end end end diff --git a/app/graphql/types/ci/pipeline_trigger_type.rb b/app/graphql/types/ci/pipeline_trigger_type.rb new file mode 100644 index 00000000000..81345c14ba0 --- /dev/null +++ b/app/graphql/types/ci/pipeline_trigger_type.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Types + module Ci + class PipelineTriggerType < BaseObject + graphql_name 'PipelineTrigger' + + present_using ::Ci::TriggerPresenter + connection_type_class Types::CountableConnectionType + + authorize :admin_build + + field :can_access_project, GraphQL::Types::Boolean, + null: false, + description: 'Indicates if the pipeline trigger token has access to the project.', + method: :can_access_project? + + field :description, GraphQL::Types::String, + null: true, + description: 'Description of the pipeline trigger token.' + + field :has_token_exposed, GraphQL::Types::Boolean, + null: false, + description: 'Indicates if the token is exposed.', + method: :has_token_exposed? + + field :id, GraphQL::Types::ID, + null: false, + description: 'ID of the pipeline trigger token.' + + field :last_used, Types::TimeType, + null: true, + description: 'Timestamp of the last usage of the pipeline trigger token.' + + field :owner, Types::UserType, + null: false, + description: 'Owner of the pipeline trigger token.' + + field :token, GraphQL::Types::String, + null: false, + description: 'Value of the pipeline trigger token.' + end + end +end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index 19d261853a7..ba638d4bc47 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -5,7 +5,7 @@ module Types class PipelineType < BaseObject graphql_name 'Pipeline' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_pipeline present_using ::Ci::PipelinePresenter diff --git a/app/graphql/types/ci/project_variable_type.rb b/app/graphql/types/ci/project_variable_type.rb index a9679000511..cd069be3320 100644 --- a/app/graphql/types/ci/project_variable_type.rb +++ b/app/graphql/types/ci/project_variable_type.rb @@ -7,8 +7,8 @@ module Types graphql_name 'CiProjectVariable' description 'CI/CD variables for a project.' - connection_type_class(Types::Ci::ProjectVariableConnectionType) - implements(VariableInterface) + connection_type_class Types::Ci::ProjectVariableConnectionType + implements VariableInterface field :environment_scope, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/ci/recent_failures_type.rb b/app/graphql/types/ci/recent_failures_type.rb index 0892cb2735c..37850c62658 100644 --- a/app/graphql/types/ci/recent_failures_type.rb +++ b/app/graphql/types/ci/recent_failures_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'RecentFailures' description 'Recent failure history of a test case.' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :count, GraphQL::Types::Int, null: true, description: 'Number of times the test case has failed in the past 14 days.' diff --git a/app/graphql/types/ci/runner_manager_type.rb b/app/graphql/types/ci/runner_manager_type.rb index 9c89b6537ea..9311836cf27 100644 --- a/app/graphql/types/ci/runner_manager_type.rb +++ b/app/graphql/types/ci/runner_manager_type.rb @@ -5,7 +5,7 @@ module Types class RunnerManagerType < BaseObject graphql_name 'CiRunnerManager' - connection_type_class(::Types::CountableConnectionType) + connection_type_class ::Types::CountableConnectionType authorize :read_runner_manager @@ -26,6 +26,11 @@ module Types description: 'ID of the runner manager.' field :ip_address, GraphQL::Types::String, null: true, description: 'IP address of the runner manager.' + field :job_execution_status, + Types::Ci::RunnerJobExecutionStatusEnum, + null: true, + description: 'Job execution status of the runner manager.', + alpha: { milestone: '16.3' } field :platform_name, GraphQL::Types::String, null: true, description: 'Platform provided by the runner manager.', method: :platform @@ -44,6 +49,16 @@ module Types def executor_name ::Ci::Runner::EXECUTOR_TYPE_TO_NAMES[runner_manager.executor_type&.to_sym] end + + def job_execution_status + BatchLoader::GraphQL.for(runner_manager.id).batch(key: :running_builds_exist) do |runner_manager_ids, loader| + statuses = ::Ci::RunnerManager.id_in(runner_manager_ids).with_running_builds.index_by(&:id) + + runner_manager_ids.each do |runner_manager_id| + loader.call(runner_manager_id, statuses[runner_manager_id] ? :running : :idle) + end + end + end end end end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 2baf64ca663..c9f92c05975 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -6,7 +6,7 @@ module Types graphql_name 'CiRunner' edge_type_class(RunnerWebUrlEdge) - connection_type_class(RunnerCountableConnectionType) + connection_type_class RunnerCountableConnectionType authorize :read_runner present_using ::Ci::RunnerPresenter @@ -59,7 +59,9 @@ module Types deprecated: { reason: "Use field in `manager` object instead", milestone: '16.2' }, description: 'IP address of the runner.' field :job_count, GraphQL::Types::Int, null: true, - description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist).", + description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to " \ + "indicate that more items exist).\n`jobCount` is an optimized version of `jobs { count }`, " \ + "and can be requested for multiple runners on the same request.", resolver: ::Resolvers::Ci::RunnerJobCountResolver field :job_execution_status, Types::Ci::RunnerJobExecutionStatusEnum, @@ -76,7 +78,6 @@ module Types description: 'Runner\'s maintenance notes.' field :managers, ::Types::Ci::RunnerManagerType.connection_type, null: true, description: 'Machines associated with the runner configuration.', - method: :runner_managers, alpha: { milestone: '15.10' } field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' @@ -173,6 +174,18 @@ module Types end end + def managers + BatchLoader::GraphQL.for(runner.id).batch(key: :runner_managers) do |runner_ids, loader| + runner_managers_by_runner_id = + ::Ci::RunnerManager.for_runner(runner_ids).order_id_desc.group_by(&:runner_id) + + runner_ids.each do |runner_id| + runner_managers = Array.wrap(runner_managers_by_runner_id[runner_id]) + loader.call(runner_id, runner_managers) + end + end + end + def job_execution_status BatchLoader::GraphQL.for(runner.id).batch(key: :running_builds_exist) do |runner_ids, loader| statuses = ::Ci::Runner.id_in(runner_ids).with_running_builds.index_by(&:id) diff --git a/app/graphql/types/ci/test_case_type.rb b/app/graphql/types/ci/test_case_type.rb index f88923215eb..78c70fbcc7c 100644 --- a/app/graphql/types/ci/test_case_type.rb +++ b/app/graphql/types/ci/test_case_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'TestCase' description 'Test case in pipeline test report.' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :status, Types::Ci::TestCaseStatusEnum, diff --git a/app/graphql/types/ci/test_suite_summary_type.rb b/app/graphql/types/ci/test_suite_summary_type.rb index 8801501c8d4..a98c47c6a30 100644 --- a/app/graphql/types/ci/test_suite_summary_type.rb +++ b/app/graphql/types/ci/test_suite_summary_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'TestSuiteSummary' description 'Test suite summary in a pipeline test report.' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :name, GraphQL::Types::String, null: true, description: 'Name of the test suite.' diff --git a/app/graphql/types/ci/test_suite_type.rb b/app/graphql/types/ci/test_suite_type.rb index 8845338ed6d..a5cc6282abc 100644 --- a/app/graphql/types/ci/test_suite_type.rb +++ b/app/graphql/types/ci/test_suite_type.rb @@ -7,7 +7,7 @@ module Types graphql_name 'TestSuite' description 'Test suite in a pipeline test report.' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :name, GraphQL::Types::String, null: true, description: 'Name of the test suite.' diff --git a/app/graphql/types/clusters/agent_activity_event_type.rb b/app/graphql/types/clusters/agent_activity_event_type.rb index 1d0ec7c4959..8c7dfa9c10a 100644 --- a/app/graphql/types/clusters/agent_activity_event_type.rb +++ b/app/graphql/types/clusters/agent_activity_event_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_cluster_agent - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :recorded_at, Types::TimeType, diff --git a/app/graphql/types/clusters/agent_token_type.rb b/app/graphql/types/clusters/agent_token_type.rb index 720ee2f685b..260c634e12e 100644 --- a/app/graphql/types/clusters/agent_token_type.rb +++ b/app/graphql/types/clusters/agent_token_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_cluster_agent - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :cluster_agent, Types::Clusters::AgentType, diff --git a/app/graphql/types/clusters/agent_type.rb b/app/graphql/types/clusters/agent_type.rb index 317a1aab628..c0989796141 100644 --- a/app/graphql/types/clusters/agent_type.rb +++ b/app/graphql/types/clusters/agent_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_cluster_agent - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :created_at, Types::TimeType, diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index 5dd862c7388..9f83e955f4c 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -8,7 +8,7 @@ module Types present_using CommitPresenter - implements(Types::TodoableInterface) + implements Types::TodoableInterface field :id, type: GraphQL::Types::ID, null: false, description: 'ID (global ID) of the commit.' @@ -34,6 +34,9 @@ module Types field :authored_date, type: Types::TimeType, null: true, description: 'Timestamp of when the commit was authored.' + field :committed_date, type: Types::TimeType, null: true, + description: 'Timestamp of when the commit was committed.' + field :web_url, type: GraphQL::Types::String, null: false, description: 'Web URL of the commit.' @@ -55,10 +58,24 @@ module Types field :author_name, type: GraphQL::Types::String, null: true, description: 'Commit authors name.' + field :committer_email, type: GraphQL::Types::String, null: true, + description: "Email of the committer." + + field :committer_name, type: GraphQL::Types::String, null: true, + description: "Name of the committer." + # models/commit lazy loads the author by email field :author, type: Types::UserType, null: true, description: 'Author of the commit.' + field :diffs, [Types::DiffType], null: true, calls_gitaly: true, + description: 'Diffs contained within the commit. ' \ + 'This field can only be resolved for 10 diffs in any single request.' do + # Limited to 10 calls per GraphQL request as calling `diffs` multiple times will + # lead to N+1 queries to Gitaly. + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 10 + end + field :pipelines, null: true, description: 'Pipelines of the commit ordered latest first.', @@ -68,6 +85,10 @@ module Types markdown_field :full_title_html, null: true markdown_field :description_html, null: true + def diffs + object.diffs.diffs + end + def author_gravatar GravatarService.new.execute(object.author_email, 40) end diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb index 379a0c44d67..b02cd56e6df 100644 --- a/app/graphql/types/custom_emoji_type.rb +++ b/app/graphql/types/custom_emoji_type.rb @@ -7,6 +7,10 @@ module Types authorize :read_custom_emoji + connection_type_class(Types::CountableConnectionType) + + expose_permissions Types::PermissionTypes::CustomEmoji + field :id, ::Types::GlobalIDType[::CustomEmoji], null: false, description: 'ID of the emoji.' @@ -23,5 +27,9 @@ module Types field :external, GraphQL::Types::Boolean, null: false, description: 'Whether the emoji is an external link.' + + field :created_at, Types::TimeType, + null: false, + description: 'Timestamp of when the custom emoji was created.' end end diff --git a/app/graphql/types/deployment_type.rb b/app/graphql/types/deployment_type.rb index 6d895cc81cf..c49633275fb 100644 --- a/app/graphql/types/deployment_type.rb +++ b/app/graphql/types/deployment_type.rb @@ -54,8 +54,7 @@ module Types field :job, Types::Ci::JobType, - description: 'Pipeline job of the deployment.', - method: :build + description: 'Pipeline job of the deployment.' field :triggerer, Types::UserType, diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb index be5edd17643..d253ca8bfea 100644 --- a/app/graphql/types/design_management/design_type.rb +++ b/app/graphql/types/design_management/design_type.rb @@ -10,10 +10,10 @@ module Types alias_method :design, :object - implements(Types::Notes::NoteableInterface) - implements(Types::DesignManagement::DesignFields) - implements(Types::CurrentUserTodos) - implements(Types::TodoableInterface) + implements Types::Notes::NoteableInterface + implements Types::DesignManagement::DesignFields + implements Types::CurrentUserTodos + implements Types::TodoableInterface field :description, GraphQL::Types::String, diff --git a/app/graphql/types/diff_type.rb b/app/graphql/types/diff_type.rb new file mode 100644 index 00000000000..1c67c8c645a --- /dev/null +++ b/app/graphql/types/diff_type.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + class DiffType < BaseObject + graphql_name 'Diff' + + field :a_mode, GraphQL::Types::String, null: true, + description: 'Old file mode of the file.' + field :b_mode, GraphQL::Types::String, null: true, + description: 'New file mode of the file.' + field :deleted_file, GraphQL::Types::String, null: true, + description: 'Indicates if the file has been removed. ' + field :diff, GraphQL::Types::String, null: true, + description: 'Diff representation of the changes made to the file.' + field :new_file, GraphQL::Types::String, null: true, + description: 'Indicates if the file has just been added. ' + field :new_path, GraphQL::Types::String, null: true, + description: 'New path of the file.' + field :old_path, GraphQL::Types::String, null: true, + description: 'Old path of the file.' + field :renamed_file, GraphQL::Types::String, null: true, + description: 'Indicates if the file has been renamed.' + end + # rubocop: enable Graphql/AuthorizeTypes +end diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb index aee09e5a143..63f2b247e01 100644 --- a/app/graphql/types/environment_type.rb +++ b/app/graphql/types/environment_type.rb @@ -36,6 +36,9 @@ module Types field :kubernetes_namespace, GraphQL::Types::String, null: true, description: 'Kubernetes namespace of the environment.' + field :flux_resource_path, GraphQL::Types::String, null: true, + description: 'Flux resource path of the environment.' + field :created_at, Types::TimeType, description: 'When the environment was created.' diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 5fd6ee948d3..258cf1539fb 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -87,6 +87,7 @@ module Types Types::Ci::GroupEnvironmentScopeType.connection_type, description: 'Environment scopes of the group.', null: true, + authorize: :admin_group, resolver: Resolvers::GroupEnvironmentScopesResolver field :milestones, @@ -261,6 +262,17 @@ module Types resolver: Resolvers::DataTransfer::GroupDataTransferResolver, description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.' + field :work_items, + null: true, + description: 'Work items that belong to the namespace.', + alpha: { milestone: '16.3' }, + resolver: ::Resolvers::Namespaces::WorkItemsResolver + + field :autocomplete_users, + null: true, + resolver: Resolvers::AutocompleteUsersResolver, + description: 'Search users for autocompletion' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| LabelsFinder diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 488e4d10cbc..4b7118d75a5 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -4,11 +4,11 @@ module Types class IssueType < BaseObject graphql_name 'Issue' - connection_type_class(Types::IssueConnectionType) + connection_type_class Types::IssueConnectionType - implements(Types::Notes::NoteableInterface) - implements(Types::CurrentUserTodos) - implements(Types::TodoableInterface) + implements Types::Notes::NoteableInterface + implements Types::CurrentUserTodos + implements Types::TodoableInterface authorize :read_issue @@ -92,7 +92,13 @@ module Types field :emails_disabled, GraphQL::Types::Boolean, null: false, method: :project_emails_disabled?, - description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.' + description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.', + deprecated: { reason: 'Use `emails_enabled`', milestone: '16.3' } + + field :emails_enabled, GraphQL::Types::Boolean, null: false, + method: :project_emails_enabled?, + description: 'Indicates if a project has email notifications disabled: `false` if email notifications are disabled.' + field :human_time_estimate, GraphQL::Types::String, null: true, description: 'Human-readable time estimate of the issue.' field :human_total_time_spent, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index 05b703e60af..4848ee30950 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -4,7 +4,7 @@ module Types class LabelType < BaseObject graphql_name 'Label' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_label diff --git a/app/graphql/types/merge_request_state_enum.rb b/app/graphql/types/merge_request_state_enum.rb index bcf18b836de..e03b79dfeb8 100644 --- a/app/graphql/types/merge_request_state_enum.rb +++ b/app/graphql/types/merge_request_state_enum.rb @@ -5,6 +5,7 @@ module Types graphql_name 'MergeRequestState' description 'State of a GitLab merge request' - value 'merged', description: "Merge request has been merged." + value 'merged', description: 'Merge request has been merged.' + value 'opened', description: 'Opened merge request.' end end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 99c719f1402..3fe8a05b311 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -4,11 +4,11 @@ module Types class MergeRequestType < BaseObject graphql_name 'MergeRequest' - connection_type_class(Types::MergeRequestConnectionType) + connection_type_class Types::MergeRequestConnectionType - implements(Types::Notes::NoteableInterface) - implements(Types::CurrentUserTodos) - implements(Types::TodoableInterface) + implements Types::Notes::NoteableInterface + implements Types::CurrentUserTodos + implements Types::TodoableInterface authorize :read_merge_request @@ -192,6 +192,11 @@ module Types field :total_time_spent, GraphQL::Types::Int, null: false, description: 'Total time reported as spent on the merge request.' + field :approved, GraphQL::Types::Boolean, + method: :approved?, + null: false, calls_gitaly: true, + description: 'Indicates if the merge request has all the required approvals.' + field :approved_by, Types::UserType.connection_type, null: true, description: 'Users who approved the merge request.', method: :approved_by_users field :auto_merge_strategy, GraphQL::Types::String, null: true, @@ -221,7 +226,7 @@ module Types field :award_emoji, Types::AwardEmojis::AwardEmojiType.connection_type, null: true, - description: 'List of award emojis associated with the merge request.' + description: 'List of emoji reactions associated with the merge request.' field :prepared_at, Types::TimeType, null: true, description: 'Timestamp of when the merge request was prepared.' diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 16c46d172f3..957fd10690f 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -143,6 +143,9 @@ module Types mount_mutation Mutations::Ci::PipelineSchedule::Play mount_mutation Mutations::Ci::PipelineSchedule::Create mount_mutation Mutations::Ci::PipelineSchedule::Update + mount_mutation Mutations::Ci::PipelineTrigger::Create, alpha: { milestone: '16.3' } + mount_mutation Mutations::Ci::PipelineTrigger::Update, alpha: { milestone: '16.3' } + mount_mutation Mutations::Ci::PipelineTrigger::Delete, alpha: { milestone: '16.3' } mount_mutation Mutations::Ci::ProjectCiCdSettingsUpdate mount_mutation Mutations::Ci::Job::ArtifactsDestroy mount_mutation Mutations::Ci::Job::Play @@ -177,12 +180,14 @@ module Types mount_mutation Mutations::WorkItems::UpdateTask, alpha: { milestone: '15.1' } mount_mutation Mutations::WorkItems::Export, alpha: { milestone: '15.10' } mount_mutation Mutations::WorkItems::Convert, alpha: { milestone: '15.11' } + mount_mutation Mutations::WorkItems::LinkedItems::Add, alpha: { milestone: '16.3' } mount_mutation Mutations::SavedReplies::Create mount_mutation Mutations::SavedReplies::Update mount_mutation Mutations::Pages::MarkOnboardingComplete mount_mutation Mutations::SavedReplies::Destroy mount_mutation Mutations::Uploads::Delete mount_mutation Mutations::Users::SetNamespaceCommitEmail + mount_mutation Mutations::WorkItems::Subscribe, alpha: { milestone: '16.3' } end end diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb index 84becba8001..61240243b1f 100644 --- a/app/graphql/types/namespace/package_settings_type.rb +++ b/app/graphql/types/namespace/package_settings_type.rb @@ -20,6 +20,14 @@ module Types field :maven_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' + field :nuget_duplicate_exception_regex, Types::UntrustedRegexp, + null: true, + description: 'When nuget_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. ' \ + 'Error is raised if `nuget_duplicates_option` feature flag is disabled.' + field :nuget_duplicates_allowed, GraphQL::Types::Boolean, + null: false, + description: 'Indicates whether duplicate NuGet packages are allowed for this namespace. ' \ + 'Error is raised if `nuget_duplicates_option` feature flag is disabled.' field :maven_package_requests_forwarding, GraphQL::Types::Boolean, null: true, diff --git a/app/graphql/types/notes/discussion_type.rb b/app/graphql/types/notes/discussion_type.rb index 5e40c8008a9..7afb1f392d3 100644 --- a/app/graphql/types/notes/discussion_type.rb +++ b/app/graphql/types/notes/discussion_type.rb @@ -9,7 +9,7 @@ module Types authorize :read_note - implements(Types::ResolvableInterface) + implements Types::ResolvableInterface field :created_at, Types::TimeType, null: false, description: "Timestamp of the discussion's creation." diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index eb1963f976a..e7e032c67c6 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -9,7 +9,7 @@ module Types expose_permissions Types::PermissionTypes::Note - implements(Types::ResolvableInterface) + implements Types::ResolvableInterface field :max_access_level_of_author, GraphQL::Types::String, null: true, @@ -43,7 +43,7 @@ module Types field :award_emoji, Types::AwardEmojis::AwardEmojiType.connection_type, null: true, - description: 'List of award emojis associated with the note.' + description: 'List of emoji reactions associated with the note.' field :confidential, GraphQL::Types::Boolean, null: true, diff --git a/app/graphql/types/notes/position_type_enum.rb b/app/graphql/types/notes/position_type_enum.rb index 157b0b4b884..b585d531192 100644 --- a/app/graphql/types/notes/position_type_enum.rb +++ b/app/graphql/types/notes/position_type_enum.rb @@ -8,6 +8,7 @@ module Types value 'text', description: "Text file." value 'image', description: "An image." + value 'file', description: "Unknown file type." end end end diff --git a/app/graphql/types/packages/package_base_type.rb b/app/graphql/types/packages/package_base_type.rb index 8dd2a4467d6..cc41169bcda 100644 --- a/app/graphql/types/packages/package_base_type.rb +++ b/app/graphql/types/packages/package_base_type.rb @@ -6,7 +6,7 @@ module Types graphql_name 'PackageBase' description 'Represents a package in the Package Registry' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_package diff --git a/app/graphql/types/permission_types/group.rb b/app/graphql/types/permission_types/group.rb index 6a1031e2532..fbd1140babc 100644 --- a/app/graphql/types/permission_types/group.rb +++ b/app/graphql/types/permission_types/group.rb @@ -5,7 +5,7 @@ module Types class Group < BasePermissionType graphql_name 'GroupPermissions' - abilities :read_group, :create_projects + abilities :read_group, :create_projects, :create_custom_emoji end end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 992663b4d98..2738d4da6c2 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -4,618 +4,625 @@ module Types class ProjectType < BaseObject graphql_name 'Project' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_project expose_permissions Types::PermissionTypes::Project field :id, GraphQL::Types::ID, - null: false, - description: 'ID of the project.' + null: false, + description: 'ID of the project.' field :ci_config_path_or_default, GraphQL::Types::String, - null: false, - description: 'Path of the CI configuration file.' + null: false, + description: 'Path of the CI configuration file.' field :ci_config_variables, [Types::Ci::ConfigVariableType], - null: true, - calls_gitaly: true, - authorize: :create_pipeline, - alpha: { milestone: '15.3' }, - description: 'CI/CD config variable.' do - argument :ref, GraphQL::Types::String, - required: true, - description: 'Ref.' - end + null: true, + calls_gitaly: true, + authorize: :create_pipeline, + alpha: { milestone: '15.3' }, + description: 'CI/CD config variable.' do + argument :ref, GraphQL::Types::String, + required: true, + description: 'Ref.' + end field :full_path, GraphQL::Types::ID, - null: false, - description: 'Full path of the project.' + null: false, + description: 'Full path of the project.' field :path, GraphQL::Types::String, - null: false, - description: 'Path of the project.' + null: false, + description: 'Path of the project.' field :incident_management_timeline_event_tags, [Types::IncidentManagement::TimelineEventTagType], - null: true, - description: 'Timeline event tags for the project.' + null: true, + description: 'Timeline event tags for the project.' field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, - null: true, - calls_gitaly: true, - description: 'SAST CI configuration for the project.' + null: true, + calls_gitaly: true, + description: 'SAST CI configuration for the project.' field :name, GraphQL::Types::String, - null: false, - description: 'Name of the project (without namespace).' + null: false, + description: 'Name of the project (without namespace).' field :name_with_namespace, GraphQL::Types::String, - null: false, - description: 'Full name of the project with its namespace.' + null: false, + description: 'Full name of the project with its namespace.' field :description, GraphQL::Types::String, - null: true, - description: 'Short description of the project.' + null: true, + description: 'Short description of the project.' field :tag_list, GraphQL::Types::String, - null: true, - deprecated: { reason: 'Use `topics`', milestone: '13.12' }, - description: 'List of project topics (not Git tags).', - method: :topic_list + null: true, + deprecated: { reason: 'Use `topics`', milestone: '13.12' }, + description: 'List of project topics (not Git tags).', + method: :topic_list field :topics, [GraphQL::Types::String], - null: true, - description: 'List of project topics.', - method: :topic_list + null: true, + description: 'List of project topics.', + method: :topic_list field :http_url_to_repo, GraphQL::Types::String, - null: true, - description: 'URL to connect to the project via HTTPS.' + null: true, + description: 'URL to connect to the project via HTTPS.' field :ssh_url_to_repo, GraphQL::Types::String, - null: true, - description: 'URL to connect to the project via SSH.' + null: true, + description: 'URL to connect to the project via SSH.' field :web_url, GraphQL::Types::String, - null: true, - description: 'Web URL of the project.' + null: true, + description: 'Web URL of the project.' field :forks_count, GraphQL::Types::Int, - null: false, - calls_gitaly: true, # 4 times - description: 'Number of times the project has been forked.' + null: false, + calls_gitaly: true, # 4 times + description: 'Number of times the project has been forked.' field :star_count, GraphQL::Types::Int, - null: false, - description: 'Number of times the project has been starred.' + null: false, + description: 'Number of times the project has been starred.' field :created_at, Types::TimeType, - null: true, - description: 'Timestamp of the project creation.' + null: true, + description: 'Timestamp of the project creation.' field :last_activity_at, Types::TimeType, - null: true, - description: 'Timestamp of the project last activity.' + null: true, + description: 'Timestamp of the project last activity.' field :archived, GraphQL::Types::Boolean, - null: true, - description: 'Indicates the archived status of the project.' + null: true, + description: 'Indicates the archived status of the project.' field :visibility, GraphQL::Types::String, - null: true, - description: 'Visibility of the project.' + null: true, + description: 'Visibility of the project.' field :lfs_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if the project has Large File Storage (LFS) enabled.' + null: true, + description: 'Indicates if the project has Large File Storage (LFS) enabled.' field :merge_requests_ff_only_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if no merge commits should be created and all merges should instead be ' \ - 'fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.' + null: true, + description: 'Indicates if no merge commits should be created and all merges should instead be ' \ + 'fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.' field :shared_runners_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if shared runners are enabled for the project.' + null: true, + description: 'Indicates if shared runners are enabled for the project.' field :service_desk_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if the project has Service Desk enabled.' + null: true, + description: 'Indicates if the project has Service Desk enabled.' field :service_desk_address, GraphQL::Types::String, - null: true, - description: 'E-mail address of the Service Desk.' + null: true, + description: 'E-mail address of the Service Desk.' field :avatar_url, GraphQL::Types::String, - null: true, - calls_gitaly: true, - description: 'URL to avatar image file of the project.' + null: true, + calls_gitaly: true, + description: 'URL to avatar image file of the project.' field :jobs_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if CI/CD pipeline jobs are enabled for the current user.' + null: true, + description: 'Indicates if CI/CD pipeline jobs are enabled for the current user.' field :is_catalog_resource, GraphQL::Types::Boolean, - alpha: { milestone: '15.11' }, - null: true, - description: 'Indicates if a project is a catalog resource.' + alpha: { milestone: '15.11' }, + null: true, + description: 'Indicates if a project is a catalog resource.' field :public_jobs, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if there is public access to pipelines and job details of the project, ' \ - 'including output logs and artifacts.', - method: :public_builds + null: true, + description: 'Indicates if there is public access to pipelines and job details of the project, ' \ + 'including output logs and artifacts.', + method: :public_builds field :open_issues_count, GraphQL::Types::Int, - null: true, - description: 'Number of open issues for the project.' + null: true, + description: 'Number of open issues for the project.' field :allow_merge_on_skipped_pipeline, GraphQL::Types::Boolean, - null: true, - description: 'If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of ' \ - 'the project can also be merged with skipped jobs.' + null: true, + description: 'If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of ' \ + 'the project can also be merged with skipped jobs.' field :autoclose_referenced_issues, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if issues referenced by merge requests and commits within the default branch ' \ - 'are closed automatically.' + null: true, + description: 'Indicates if issues referenced by merge requests and commits within the default branch ' \ + 'are closed automatically.' field :import_status, GraphQL::Types::String, - null: true, - description: 'Status of import background job of the project.' + null: true, + description: 'Status of import background job of the project.' field :jira_import_status, GraphQL::Types::String, - null: true, - description: 'Status of Jira import background job of the project.' + null: true, + description: 'Status of Jira import background job of the project.' field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved.' + null: true, + description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved.' field :only_allow_merge_if_pipeline_succeeds, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if merge requests of the project can only be merged with successful jobs.' + null: true, + description: 'Indicates if merge requests of the project can only be merged with successful jobs.' field :printing_merge_request_link_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if a link to create or view a merge request should display after a push to Git ' \ - 'repositories of the project from the command line.' + null: true, + description: 'Indicates if a link to create or view a merge request should display after a push to Git ' \ + 'repositories of the project from the command line.' field :remove_source_branch_after_merge, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if `Delete source branch` option should be enabled by default for all ' \ - 'new merge requests of the project.' + null: true, + description: 'Indicates if `Delete source branch` option should be enabled by default for all ' \ + 'new merge requests of the project.' field :request_access_enabled, GraphQL::Types::Boolean, - null: true, - description: 'Indicates if users can request member access to the project.' + null: true, + description: 'Indicates if users can request member access to the project.' field :squash_read_only, GraphQL::Types::Boolean, - null: false, - description: 'Indicates if `squashReadOnly` is enabled.', - method: :squash_readonly? + null: false, + description: 'Indicates if `squashReadOnly` is enabled.', + method: :squash_readonly? field :suggestion_commit_message, GraphQL::Types::String, - null: true, - description: 'Commit message used to apply merge request suggestions.' + null: true, + description: 'Commit message used to apply merge request suggestions.' # No, the quotes are not a typo. Used to get around circular dependencies. # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27536#note_871009675 field :group, 'Types::GroupType', - null: true, - description: 'Group of the project.' + null: true, + description: 'Group of the project.' field :namespace, Types::NamespaceType, - null: true, - description: 'Namespace of the project.' + null: true, + description: 'Namespace of the project.' field :statistics, Types::ProjectStatisticsType, - null: true, - description: 'Statistics of the project.' + null: true, + description: 'Statistics of the project.' field :statistics_details_paths, Types::ProjectStatisticsRedirectType, - null: true, - description: 'Redirects for Statistics of the project.', - calls_gitaly: true + null: true, + description: 'Redirects for Statistics of the project.', + calls_gitaly: true field :repository, Types::RepositoryType, - null: true, - description: 'Git repository of the project.' + null: true, + description: 'Git repository of the project.' field :merge_requests, - Types::MergeRequestType.connection_type, - null: true, - description: 'Merge requests of the project.', - extras: [:lookahead], - resolver: Resolvers::ProjectMergeRequestsResolver + Types::MergeRequestType.connection_type, + null: true, + description: 'Merge requests of the project.', + extras: [:lookahead], + resolver: Resolvers::ProjectMergeRequestsResolver field :merge_request, - Types::MergeRequestType, - null: true, - description: 'A single merge request of the project.', - resolver: Resolvers::MergeRequestsResolver.single + Types::MergeRequestType, + null: true, + description: 'A single merge request of the project.', + resolver: Resolvers::MergeRequestsResolver.single field :issues, - Types::IssueType.connection_type, - null: true, - description: 'Issues of the project.', - resolver: Resolvers::ProjectIssuesResolver + Types::IssueType.connection_type, + null: true, + description: 'Issues of the project.', + resolver: Resolvers::ProjectIssuesResolver field :work_items, - Types::WorkItemType.connection_type, - null: true, - alpha: { milestone: '15.1' }, - description: 'Work items of the project.', - extras: [:lookahead], - resolver: Resolvers::WorkItemsResolver + Types::WorkItemType.connection_type, + null: true, + alpha: { milestone: '15.1' }, + description: 'Work items of the project.', + extras: [:lookahead], + resolver: Resolvers::WorkItemsResolver field :issue_status_counts, - Types::IssueStatusCountsType, - null: true, - description: 'Counts of issues by status for the project.', - resolver: Resolvers::IssueStatusCountsResolver + Types::IssueStatusCountsType, + null: true, + description: 'Counts of issues by status for the project.', + resolver: Resolvers::IssueStatusCountsResolver field :milestones, Types::MilestoneType.connection_type, - null: true, - description: 'Milestones of the project.', - resolver: Resolvers::ProjectMilestonesResolver + null: true, + description: 'Milestones of the project.', + resolver: Resolvers::ProjectMilestonesResolver field :project_members, - description: 'Members of the project.', - resolver: Resolvers::ProjectMembersResolver + description: 'Members of the project.', + resolver: Resolvers::ProjectMembersResolver field :environments, - Types::EnvironmentType.connection_type, - null: true, - description: 'Environments of the project. ' \ - 'This field can only be resolved for one project in any single request.', - resolver: Resolvers::EnvironmentsResolver do - extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 - end + Types::EnvironmentType.connection_type, + null: true, + description: 'Environments of the project. ' \ + 'This field can only be resolved for one project in any single request.', + resolver: Resolvers::EnvironmentsResolver do + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + end field :environment, - Types::EnvironmentType, - null: true, - description: 'A single environment of the project.', - resolver: Resolvers::EnvironmentsResolver.single + Types::EnvironmentType, + null: true, + description: 'A single environment of the project.', + resolver: Resolvers::EnvironmentsResolver.single field :nested_environments, - Types::NestedEnvironmentType.connection_type, - null: true, - calls_gitaly: true, - description: 'Environments for this project with nested folders, ' \ - 'can only be resolved for one project in any single request', - resolver: Resolvers::Environments::NestedEnvironmentsResolver do - extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 - end + Types::NestedEnvironmentType.connection_type, + null: true, + calls_gitaly: true, + description: 'Environments for this project with nested folders, ' \ + 'can only be resolved for one project in any single request', + resolver: Resolvers::Environments::NestedEnvironmentsResolver do + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + end field :deployment, - Types::DeploymentType, - null: true, - description: 'Details of the deployment of the project.', - resolver: Resolvers::DeploymentResolver.single + Types::DeploymentType, + null: true, + description: 'Details of the deployment of the project.', + resolver: Resolvers::DeploymentResolver.single field :issue, - Types::IssueType, - null: true, - description: 'A single issue of the project.', - resolver: Resolvers::ProjectIssuesResolver.single + Types::IssueType, + null: true, + description: 'A single issue of the project.', + resolver: Resolvers::ProjectIssuesResolver.single field :packages, - description: 'Packages of the project.', - resolver: Resolvers::ProjectPackagesResolver + description: 'Packages of the project.', + resolver: Resolvers::ProjectPackagesResolver field :packages_cleanup_policy, - Types::Packages::Cleanup::PolicyType, - null: true, - description: 'Packages cleanup policy for the project.' + Types::Packages::Cleanup::PolicyType, + null: true, + description: 'Packages cleanup policy for the project.' field :jobs, - type: Types::Ci::JobType.connection_type, - null: true, - authorize: :read_build, - description: 'Jobs of a project. This field can only be resolved for one project in any single request.', - resolver: Resolvers::ProjectJobsResolver + type: Types::Ci::JobType.connection_type, + null: true, + authorize: :read_build, + description: 'Jobs of a project. This field can only be resolved for one project in any single request.', + resolver: Resolvers::ProjectJobsResolver field :job, - type: Types::Ci::JobType, - null: true, - authorize: :read_build, - description: 'One job belonging to the project, selected by ID.' do - argument :id, Types::GlobalIDType[::CommitStatus], - required: true, - description: 'ID of the job.' - end + type: Types::Ci::JobType, + null: true, + authorize: :read_build, + description: 'One job belonging to the project, selected by ID.' do + argument :id, Types::GlobalIDType[::CommitStatus], + required: true, + description: 'ID of the job.' + end field :pipelines, - null: true, - description: 'Build pipelines of the project.', - extras: [:lookahead], - resolver: Resolvers::ProjectPipelinesResolver + null: true, + description: 'Build pipelines of the project.', + extras: [:lookahead], + resolver: Resolvers::ProjectPipelinesResolver field :pipeline_schedules, - type: Types::Ci::PipelineScheduleType.connection_type, - null: true, - description: 'Pipeline schedules of the project. This field can only be resolved for one project per request.', - resolver: Resolvers::ProjectPipelineSchedulesResolver + type: Types::Ci::PipelineScheduleType.connection_type, + null: true, + description: 'Pipeline schedules of the project. This field can only be resolved for one project per request.', + resolver: Resolvers::ProjectPipelineSchedulesResolver + + field :pipeline_triggers, + Types::Ci::PipelineTriggerType.connection_type, + null: true, + description: 'List of pipeline trigger tokens.', + resolver: Resolvers::Ci::PipelineTriggersResolver, + alpha: { milestone: '16.3' } field :pipeline, Types::Ci::PipelineType, - null: true, - description: 'Build pipeline of the project.', - extras: [:lookahead], - resolver: Resolvers::ProjectPipelineResolver + null: true, + description: 'Build pipeline of the project.', + extras: [:lookahead], + resolver: Resolvers::ProjectPipelineResolver field :pipeline_counts, Types::Ci::PipelineCountsType, - null: true, - description: 'Build pipeline counts of the project.', - resolver: Resolvers::Ci::ProjectPipelineCountsResolver + null: true, + description: 'Build pipeline counts of the project.', + resolver: Resolvers::Ci::ProjectPipelineCountsResolver field :ci_variables, Types::Ci::ProjectVariableType.connection_type, - null: true, - description: "List of the project's CI/CD variables.", - authorize: :admin_build, - resolver: Resolvers::Ci::VariablesResolver + null: true, + description: "List of the project's CI/CD variables.", + authorize: :admin_build, + resolver: Resolvers::Ci::VariablesResolver field :inherited_ci_variables, Types::Ci::InheritedCiVariableType.connection_type, - null: true, - description: "List of CI/CD variables the project inherited from its parent group and ancestors.", - authorize: :admin_build, - resolver: Resolvers::Ci::InheritedVariablesResolver + null: true, + description: "List of CI/CD variables the project inherited from its parent group and ancestors.", + authorize: :admin_build, + resolver: Resolvers::Ci::InheritedVariablesResolver field :ci_cd_settings, Types::Ci::CiCdSettingType, - null: true, - description: 'CI/CD settings for the project.' + null: true, + description: 'CI/CD settings for the project.' field :sentry_detailed_error, Types::ErrorTracking::SentryDetailedErrorType, - null: true, - description: 'Detailed version of a Sentry error on the project.', - resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver + null: true, + description: 'Detailed version of a Sentry error on the project.', + resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver field :grafana_integration, Types::GrafanaIntegrationType, - null: true, - description: 'Grafana integration details for the project.', - resolver: Resolvers::Projects::GrafanaIntegrationResolver + null: true, + description: 'Grafana integration details for the project.', + resolver: Resolvers::Projects::GrafanaIntegrationResolver field :snippets, Types::SnippetType.connection_type, - null: true, - description: 'Snippets of the project.', - resolver: Resolvers::Projects::SnippetsResolver + null: true, + description: 'Snippets of the project.', + resolver: Resolvers::Projects::SnippetsResolver field :sentry_errors, Types::ErrorTracking::SentryErrorCollectionType, - null: true, - description: 'Paginated collection of Sentry errors on the project.', - resolver: Resolvers::ErrorTracking::SentryErrorCollectionResolver + null: true, + description: 'Paginated collection of Sentry errors on the project.', + resolver: Resolvers::ErrorTracking::SentryErrorCollectionResolver field :boards, Types::BoardType.connection_type, - null: true, - description: 'Boards of the project.', - max_page_size: 2000, - resolver: Resolvers::BoardsResolver + null: true, + description: 'Boards of the project.', + 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 + null: true, + description: 'List of recently visited boards of the project. Maximum size is 4.', + resolver: Resolvers::RecentBoardsResolver field :board, Types::BoardType, - null: true, - description: 'A single board of the project.', - resolver: Resolvers::BoardResolver + null: true, + description: 'A single board of the project.', + resolver: Resolvers::BoardResolver field :jira_imports, Types::JiraImportType.connection_type, - null: true, - description: 'Jira imports into the project.' + null: true, + description: 'Jira imports into the project.' field :services, Types::Projects::ServiceType.connection_type, - null: true, - deprecated: { - reason: 'This will be renamed to `Project.integrations`', - milestone: '15.9' - }, - description: 'Project services.', - resolver: Resolvers::Projects::ServicesResolver + null: true, + deprecated: { + reason: 'This will be renamed to `Project.integrations`', + milestone: '15.9' + }, + description: 'Project services.', + resolver: Resolvers::Projects::ServicesResolver field :alert_management_alerts, Types::AlertManagement::AlertType.connection_type, - null: true, - description: 'Alert Management alerts of the project.', - extras: [:lookahead], - resolver: Resolvers::AlertManagement::AlertResolver + null: true, + description: 'Alert Management alerts of the project.', + extras: [:lookahead], + resolver: Resolvers::AlertManagement::AlertResolver field :alert_management_alert, Types::AlertManagement::AlertType, - null: true, - description: 'A single Alert Management alert of the project.', - resolver: Resolvers::AlertManagement::AlertResolver.single + null: true, + description: 'A single Alert Management alert of the project.', + resolver: Resolvers::AlertManagement::AlertResolver.single field :alert_management_alert_status_counts, Types::AlertManagement::AlertStatusCountsType, - null: true, - description: 'Counts of alerts by status for the project.', - resolver: Resolvers::AlertManagement::AlertStatusCountsResolver + null: true, + description: 'Counts of alerts by status for the project.', + resolver: Resolvers::AlertManagement::AlertStatusCountsResolver field :alert_management_integrations, Types::AlertManagement::IntegrationType.connection_type, - null: true, - description: 'Integrations which can receive alerts for the project.', - resolver: Resolvers::AlertManagement::IntegrationsResolver + null: true, + description: 'Integrations which can receive alerts for the project.', + resolver: Resolvers::AlertManagement::IntegrationsResolver field :alert_management_http_integrations, Types::AlertManagement::HttpIntegrationType.connection_type, - null: true, - description: 'HTTP Integrations which can receive alerts for the project.', - resolver: Resolvers::AlertManagement::HttpIntegrationsResolver + null: true, + description: 'HTTP Integrations which can receive alerts for the project.', + resolver: Resolvers::AlertManagement::HttpIntegrationsResolver field :incident_management_timeline_events, Types::IncidentManagement::TimelineEventType.connection_type, - null: true, - description: 'Incident Management Timeline events associated with the incident.', - extras: [:lookahead], - resolver: Resolvers::IncidentManagement::TimelineEventsResolver + null: true, + description: 'Incident Management Timeline events associated with the incident.', + extras: [:lookahead], + resolver: Resolvers::IncidentManagement::TimelineEventsResolver field :incident_management_timeline_event, Types::IncidentManagement::TimelineEventType, - null: true, - description: 'Incident Management Timeline event associated with the incident.', - resolver: Resolvers::IncidentManagement::TimelineEventsResolver.single + null: true, + description: 'Incident Management Timeline event associated with the incident.', + resolver: Resolvers::IncidentManagement::TimelineEventsResolver.single field :releases, Types::ReleaseType.connection_type, - null: true, - description: 'Releases of the project.', - resolver: Resolvers::ReleasesResolver + null: true, + description: 'Releases of the project.', + resolver: Resolvers::ReleasesResolver field :release, Types::ReleaseType, - null: true, - description: 'A single release of the project.', - resolver: Resolvers::ReleasesResolver.single, - authorize: :read_release + null: true, + description: 'A single release of the project.', + resolver: Resolvers::ReleasesResolver.single, + authorize: :read_release field :container_expiration_policy, Types::ContainerExpirationPolicyType, - null: true, - description: 'Container expiration policy of the project.' + null: true, + description: 'Container expiration policy of the project.' field :container_repositories, Types::ContainerRepositoryType.connection_type, - null: true, - description: 'Container repositories of the project.', - resolver: Resolvers::ContainerRepositoriesResolver + null: true, + description: 'Container repositories of the project.', + resolver: Resolvers::ContainerRepositoriesResolver field :container_repositories_count, GraphQL::Types::Int, - null: false, - description: 'Number of container repositories in the project.' + null: false, + description: 'Number of container repositories in the project.' field :label, Types::LabelType, - null: true, - description: 'Label available on this project.' do - argument :title, GraphQL::Types::String, - required: true, - description: 'Title of the label.' - end + null: true, + description: 'Label available on this project.' do + argument :title, GraphQL::Types::String, + required: true, + description: 'Title of the label.' + end field :terraform_state, Types::Terraform::StateType, - null: true, - description: 'Find a single Terraform state by name.', - resolver: Resolvers::Terraform::StatesResolver.single + null: true, + description: 'Find a single Terraform state by name.', + resolver: Resolvers::Terraform::StatesResolver.single field :terraform_states, Types::Terraform::StateType.connection_type, - null: true, - description: 'Terraform states associated with the project.', - resolver: Resolvers::Terraform::StatesResolver + null: true, + description: 'Terraform states associated with the project.', + resolver: Resolvers::Terraform::StatesResolver field :pipeline_analytics, Types::Ci::AnalyticsType, - null: true, - description: 'Pipeline analytics.', - resolver: Resolvers::ProjectPipelineStatisticsResolver + null: true, + description: 'Pipeline analytics.', + resolver: Resolvers::ProjectPipelineStatisticsResolver field :ci_template, Types::Ci::TemplateType, - null: true, - description: 'Find a single CI/CD template by name.', - resolver: Resolvers::Ci::TemplateResolver + null: true, + description: 'Find a single CI/CD template by name.', + resolver: Resolvers::Ci::TemplateResolver field :ci_job_token_scope, Types::Ci::JobTokenScopeType, - null: true, - description: 'The CI Job Tokens scope of access.', - resolver: Resolvers::Ci::JobTokenScopeResolver + null: true, + description: 'The CI Job Tokens scope of access.', + resolver: Resolvers::Ci::JobTokenScopeResolver field :timelogs, Types::TimelogType.connection_type, - null: true, - description: 'Time logged on issues and merge requests in the project.', - extras: [:lookahead], - complexity: 5, - resolver: ::Resolvers::TimelogResolver + null: true, + description: 'Time logged on issues and merge requests in the project.', + extras: [:lookahead], + complexity: 5, + resolver: ::Resolvers::TimelogResolver field :agent_configurations, ::Types::Kas::AgentConfigurationType.connection_type, - null: true, - description: 'Agent configurations defined by the project', - resolver: ::Resolvers::Kas::AgentConfigurationsResolver + null: true, + description: 'Agent configurations defined by the project', + resolver: ::Resolvers::Kas::AgentConfigurationsResolver field :cluster_agent, ::Types::Clusters::AgentType, - null: true, - description: 'Find a single cluster agent by name.', - resolver: ::Resolvers::Clusters::AgentsResolver.single + null: true, + description: 'Find a single cluster agent by name.', + resolver: ::Resolvers::Clusters::AgentsResolver.single field :cluster_agents, ::Types::Clusters::AgentType.connection_type, - extras: [:lookahead], - null: true, - description: 'Cluster agents associated with the project.', - resolver: ::Resolvers::Clusters::AgentsResolver + extras: [:lookahead], + null: true, + description: 'Cluster agents associated with the project.', + resolver: ::Resolvers::Clusters::AgentsResolver field :ci_access_authorized_agents, ::Types::Clusters::Agents::Authorizations::CiAccessType.connection_type, - null: true, - description: 'Authorized cluster agents for the project through ci_access keyword.', - resolver: ::Resolvers::Clusters::Agents::Authorizations::CiAccessResolver, - authorize: :read_cluster_agent + null: true, + description: 'Authorized cluster agents for the project through ci_access keyword.', + resolver: ::Resolvers::Clusters::Agents::Authorizations::CiAccessResolver, + authorize: :read_cluster_agent field :user_access_authorized_agents, ::Types::Clusters::Agents::Authorizations::UserAccessType.connection_type, - null: true, - description: 'Authorized cluster agents for the project through user_access keyword.', - resolver: ::Resolvers::Clusters::Agents::Authorizations::UserAccessResolver, - authorize: :read_cluster_agent + null: true, + description: 'Authorized cluster agents for the project through user_access keyword.', + resolver: ::Resolvers::Clusters::Agents::Authorizations::UserAccessResolver, + authorize: :read_cluster_agent field :merge_commit_template, GraphQL::Types::String, - null: true, - description: 'Template used to create merge commit message in merge requests.' + null: true, + description: 'Template used to create merge commit message in merge requests.' field :squash_commit_template, GraphQL::Types::String, - null: true, - description: 'Template used to create squash commit message in merge requests.' + null: true, + description: 'Template used to create squash commit message in merge requests.' field :labels, Types::LabelType.connection_type, - null: true, - description: 'Labels available on this project.', - resolver: Resolvers::LabelsResolver + null: true, + description: 'Labels available on this project.', + resolver: Resolvers::LabelsResolver field :work_item_types, Types::WorkItems::TypeType.connection_type, - resolver: Resolvers::WorkItems::TypesResolver, - description: 'Work item types available to the project.' + resolver: Resolvers::WorkItems::TypesResolver, + description: 'Work item types available to the project.' field :timelog_categories, Types::TimeTracking::TimelogCategoryType.connection_type, - null: true, - description: "Timelog categories for the project.", - alpha: { milestone: '15.3' } + null: true, + description: "Timelog categories for the project.", + alpha: { milestone: '15.3' } field :fork_targets, Types::NamespaceType.connection_type, - resolver: Resolvers::Projects::ForkTargetsResolver, - description: 'Namespaces in which the current user can fork the project into.' + resolver: Resolvers::Projects::ForkTargetsResolver, + description: 'Namespaces in which the current user can fork the project into.' field :fork_details, Types::Projects::ForkDetailsType, - calls_gitaly: true, - alpha: { milestone: '15.7' }, - authorize: :read_code, - resolver: Resolvers::Projects::ForkDetailsResolver, - description: 'Details of the fork project compared to its upstream project.' + calls_gitaly: true, + alpha: { milestone: '15.7' }, + authorize: :read_code, + resolver: Resolvers::Projects::ForkDetailsResolver, + description: 'Details of the fork project compared to its upstream project.' field :branch_rules, - Types::Projects::BranchRuleType.connection_type, - null: true, - description: "Branch rules configured for the project.", - resolver: Resolvers::Projects::BranchRulesResolver + Types::Projects::BranchRuleType.connection_type, + null: true, + description: "Branch rules configured for the project.", + resolver: Resolvers::Projects::BranchRulesResolver field :languages, [Types::Projects::RepositoryLanguageType], - null: true, - description: "Programming languages used in the project.", - calls_gitaly: true + null: true, + description: "Programming languages used in the project.", + calls_gitaly: true field :runners, Types::Ci::RunnerType.connection_type, - null: true, - resolver: ::Resolvers::Ci::ProjectRunnersResolver, - description: "Find runners visible to the current user." + null: true, + resolver: ::Resolvers::Ci::ProjectRunnersResolver, + description: "Find runners visible to the current user." field :data_transfer, Types::DataTransfer::ProjectDataTransferType, - null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out! https://gitlab.com/gitlab-org/gitlab/-/issues/391682 - resolver: Resolvers::DataTransfer::ProjectDataTransferResolver, - description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.' + null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out! https://gitlab.com/gitlab-org/gitlab/-/issues/391682 + resolver: Resolvers::DataTransfer::ProjectDataTransferResolver, + description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.' field :visible_forks, Types::ProjectType.connection_type, - null: true, - alpha: { milestone: '15.10' }, - description: "Visible forks of the project." do - argument :minimum_access_level, - type: ::Types::AccessLevelEnum, - required: false, - description: 'Minimum access level.' - end + null: true, + alpha: { milestone: '15.10' }, + description: "Visible forks of the project." do + argument :minimum_access_level, + type: ::Types::AccessLevelEnum, + required: false, + description: 'Minimum access level.' + end field :flow_metrics, - ::Types::Analytics::CycleAnalytics::FlowMetrics[:project], - null: true, - description: 'Flow metrics for value stream analytics.', - method: :project_namespace, - authorize: :read_cycle_analytics, - alpha: { milestone: '15.10' } + ::Types::Analytics::CycleAnalytics::FlowMetrics[:project], + null: true, + description: 'Flow metrics for value stream analytics.', + method: :project_namespace, + authorize: :read_cycle_analytics, + alpha: { milestone: '15.10' } field :commit_references, ::Types::CommitReferencesType, null: true, @@ -623,6 +630,11 @@ module Types alpha: { milestone: '16.0' }, description: "Get tag names containing a given commit." + field :autocomplete_users, + null: true, + resolver: Resolvers::AutocompleteUsersResolver, + description: 'Search users for autocompletion' + def timelog_categories object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories) end @@ -644,7 +656,7 @@ module Types container_registry: 'Container Registry is' }.each do |feature, name_string| field "#{feature}_enabled", GraphQL::Types::Boolean, null: true, - description: "Indicates if #{name_string} enabled for the current user" + description: "Indicates if #{name_string} enabled for the current user" define_method "#{feature}_enabled" do object.feature_available?(feature, context[:current_user]) @@ -707,7 +719,7 @@ module Types if project.repository.empty? raise Gitlab::Graphql::Errors::MutationError, - Gitlab::Utils::ErrorMessage.to_user_facing(_(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe) + _(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe end ::Security::CiConfiguration::SastParserService.new(object).configuration @@ -754,11 +766,11 @@ module Types def add_file_docs_link ActionController::Base.helpers.link_to _('add at least one file to the repository'), - Rails.application.routes.url_helpers.help_page_url( - 'user/project/repository/index.md', - anchor: 'add-files-to-a-repository'), - target: '_blank', - rel: 'noopener noreferrer' + Rails.application.routes.url_helpers.help_page_url( + 'user/project/repository/index.md', + anchor: 'add-files-to-a-repository'), + target: '_blank', + rel: 'noopener noreferrer' end end end diff --git a/app/graphql/types/projects/services/base_service_type.rb b/app/graphql/types/projects/services/base_service_type.rb index 9a48aafa5a8..c77dc5c8539 100644 --- a/app/graphql/types/projects/services/base_service_type.rb +++ b/app/graphql/types/projects/services/base_service_type.rb @@ -7,7 +7,7 @@ module Types class BaseServiceType < BaseObject graphql_name 'BaseService' - implements(Types::Projects::ServiceType) + implements Types::Projects::ServiceType authorize :admin_project end diff --git a/app/graphql/types/projects/services/jira_service_type.rb b/app/graphql/types/projects/services/jira_service_type.rb index ac274d7f890..a774d381e2b 100644 --- a/app/graphql/types/projects/services/jira_service_type.rb +++ b/app/graphql/types/projects/services/jira_service_type.rb @@ -7,7 +7,7 @@ module Types class JiraServiceType < BaseObject graphql_name 'JiraService' - implements(Types::Projects::ServiceType) + implements Types::Projects::ServiceType authorize :admin_project diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index b26e447f622..38b8973034d 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -171,6 +171,18 @@ module Types description: 'Definitions for all audit events available on the instance.', resolver: Resolvers::AuditEvents::AuditEventDefinitionsResolver + field :abuse_report, ::Types::AbuseReportType, + null: true, + alpha: { milestone: '16.3' }, + description: 'Find an abuse report.', + resolver: Resolvers::AbuseReportResolver + + field :abuse_report_labels, ::Types::LabelType.connection_type, + null: true, + alpha: { milestone: '16.3' }, + description: 'Abuse report labels.', + resolver: Resolvers::AbuseReportLabelsResolver + def design_management DesignManagementObject.new(nil) end diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb index 8516256b433..0bf723bcb1b 100644 --- a/app/graphql/types/release_type.rb +++ b/app/graphql/types/release_type.rb @@ -5,7 +5,7 @@ module Types graphql_name 'Release' description 'Represents a release' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_release diff --git a/app/graphql/types/saved_reply_type.rb b/app/graphql/types/saved_reply_type.rb index 8c9f3d19810..74b3796ef8a 100644 --- a/app/graphql/types/saved_reply_type.rb +++ b/app/graphql/types/saved_reply_type.rb @@ -4,7 +4,7 @@ module Types class SavedReplyType < BaseObject graphql_name 'SavedReply' - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType authorize :read_saved_replies diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 5ee0500b1e0..6e6d0edbe15 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -5,7 +5,7 @@ module Types graphql_name 'Snippet' description 'Represents a snippet entry' - implements(Types::Notes::NoteableInterface) + implements Types::Notes::NoteableInterface present_using SnippetPresenter diff --git a/app/graphql/types/snippets/blob_type.rb b/app/graphql/types/snippets/blob_type.rb index bb4a0a64de8..2d1993225d1 100644 --- a/app/graphql/types/snippets/blob_type.rb +++ b/app/graphql/types/snippets/blob_type.rb @@ -8,7 +8,7 @@ module Types description 'Represents the snippet blob' present_using SnippetBlobPresenter - connection_type_class(Types::Snippets::BlobConnectionType) + connection_type_class Types::Snippets::BlobConnectionType field :rich_data, GraphQL::Types::String, description: 'Blob highlighted data.', diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb index be17fc41c2c..0870194a934 100644 --- a/app/graphql/types/terraform/state_type.rb +++ b/app/graphql/types/terraform/state_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_terraform_state - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType field :id, GraphQL::Types::ID, null: false, diff --git a/app/graphql/types/timelog_type.rb b/app/graphql/types/timelog_type.rb index 88baca028ef..2adf2847221 100644 --- a/app/graphql/types/timelog_type.rb +++ b/app/graphql/types/timelog_type.rb @@ -4,7 +4,7 @@ module Types class TimelogType < BaseObject graphql_name 'Timelog' - connection_type_class(Types::TimeTracking::TimelogConnectionType) + connection_type_class Types::TimeTracking::TimelogConnectionType authorize :read_issuable diff --git a/app/graphql/types/todo_action_enum.rb b/app/graphql/types/todo_action_enum.rb index fda96796c0f..45b83ea1d64 100644 --- a/app/graphql/types/todo_action_enum.rb +++ b/app/graphql/types/todo_action_enum.rb @@ -12,5 +12,6 @@ module Types value 'merge_train_removed', value: 8, description: 'Merge request authored by the user was removed from the merge train.' value 'review_requested', value: 9, description: 'Review was requested from the user.' value 'member_access_requested', value: 10, description: 'Group or project access requested from the user.' + value 'review_submitted', value: 11, description: 'Merge request authored by the user received a review.' end end diff --git a/app/graphql/types/users/autocompleted_user_type.rb b/app/graphql/types/users/autocompleted_user_type.rb new file mode 100644 index 00000000000..8a70f398954 --- /dev/null +++ b/app/graphql/types/users/autocompleted_user_type.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Types + module Users + class AutocompletedUserType < ::Types::UserType + graphql_name 'AutocompletedUser' + + authorize :read_user + + field :merge_request_interaction, Types::UserMergeRequestInteractionType, + null: true, + description: 'Merge request state related to the user.' do + argument :id, ::Types::GlobalIDType[::MergeRequest], required: true, + description: 'Global ID of the merge request.' + end + + def merge_request_interaction(id: nil) + Gitlab::Graphql::Lazy.with_value(GitlabSchema.object_from_id(id, expected_class: ::MergeRequest)) do |mr| + ::Users::MergeRequestInteraction.new(user: object.user, merge_request: mr) if mr + end + end + end + end +end diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb index 1e58781dbb9..05798ba3d2f 100644 --- a/app/graphql/types/work_item_type.rb +++ b/app/graphql/types/work_item_type.rb @@ -4,7 +4,7 @@ module Types class WorkItemType < BaseObject graphql_name 'WorkItem' - implements(Types::TodoableInterface) + implements Types::TodoableInterface authorize :read_work_item diff --git a/app/graphql/types/work_items/linked_item_type.rb b/app/graphql/types/work_items/linked_item_type.rb new file mode 100644 index 00000000000..a4dbeed7480 --- /dev/null +++ b/app/graphql/types/work_items/linked_item_type.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Types + module WorkItems + # rubocop:disable Graphql/AuthorizeTypes + class LinkedItemType < BaseObject + graphql_name 'LinkedWorkItemType' + + field :link_created_at, Types::TimeType, + description: 'Timestamp the link was created.', null: false + field :link_id, ::Types::GlobalIDType[::WorkItems::RelatedWorkItemLink], + description: 'Global ID of the link.', null: false + field :link_type, GraphQL::Types::String, + description: 'Type of link.', null: false + field :link_updated_at, Types::TimeType, + description: 'Timestamp the link was updated.', null: false + field :work_item, Types::WorkItemType, + description: 'Linked work item.', null: false + end + # rubocop:enable Graphql/AuthorizeTypes + end +end diff --git a/app/graphql/types/work_items/related_link_type_enum.rb b/app/graphql/types/work_items/related_link_type_enum.rb new file mode 100644 index 00000000000..d4bbc7cc404 --- /dev/null +++ b/app/graphql/types/work_items/related_link_type_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module WorkItems + class RelatedLinkTypeEnum < BaseEnum + graphql_name 'WorkItemRelatedLinkType' + description 'Values for work item link types' + + value 'RELATED', 'Related type.', value: 'relates_to' + end + end +end + +Types::WorkItems::RelatedLinkTypeEnum.prepend_mod_with('Types::WorkItems::RelatedLinkTypeEnum') diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb index 53ea901ea10..9f4dbdd1038 100644 --- a/app/graphql/types/work_items/widget_interface.rb +++ b/app/graphql/types/work_items/widget_interface.rb @@ -21,7 +21,8 @@ module Types ::Types::WorkItems::Widgets::NotesType, ::Types::WorkItems::Widgets::NotificationsType, ::Types::WorkItems::Widgets::CurrentUserTodosType, - ::Types::WorkItems::Widgets::AwardEmojiType + ::Types::WorkItems::Widgets::AwardEmojiType, + ::Types::WorkItems::Widgets::LinkedItemsType ].freeze def self.ce_orphan_types @@ -53,6 +54,8 @@ module Types ::Types::WorkItems::Widgets::CurrentUserTodosType when ::WorkItems::Widgets::AwardEmoji ::Types::WorkItems::Widgets::AwardEmojiType + when ::WorkItems::Widgets::LinkedItems + ::Types::WorkItems::Widgets::LinkedItemsType else raise "Unknown GraphQL type for widget #{object}" end diff --git a/app/graphql/types/work_items/widgets/award_emoji_type.rb b/app/graphql/types/work_items/widgets/award_emoji_type.rb index 421bb8f0e98..eee04696df2 100644 --- a/app/graphql/types/work_items/widgets/award_emoji_type.rb +++ b/app/graphql/types/work_items/widgets/award_emoji_type.rb @@ -8,14 +8,14 @@ module Types # rubocop:disable Graphql/AuthorizeTypes class AwardEmojiType < BaseObject graphql_name 'WorkItemWidgetAwardEmoji' - description 'Represents the award emoji widget' + description 'Represents the emoji reactions widget' implements Types::WorkItems::WidgetInterface field :award_emoji, ::Types::AwardEmojis::AwardEmojiType.connection_type, null: true, - description: 'Award emoji on the work item.' + description: 'Emoji reactions on the work item.' field :downvotes, GraphQL::Types::Int, null: false, diff --git a/app/graphql/types/work_items/widgets/linked_items_type.rb b/app/graphql/types/work_items/widgets/linked_items_type.rb new file mode 100644 index 00000000000..fa51742b9c1 --- /dev/null +++ b/app/graphql/types/work_items/widgets/linked_items_type.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Types + module WorkItems + module Widgets + # rubocop:disable Graphql/AuthorizeTypes + class LinkedItemsType < BaseObject + graphql_name 'WorkItemWidgetLinkedItems' + description 'Represents the linked items widget' + + implements Types::WorkItems::WidgetInterface + + field :linked_items, Types::WorkItems::LinkedItemType.connection_type, + null: true, complexity: 5, + alpha: { milestone: '16.3' }, + description: 'Linked items for the work item. Returns `null`' \ + 'if `linked_work_items` feature flag is disabled.', + resolver: Resolvers::WorkItems::LinkedItemsResolver + end + # rubocop:enable Graphql/AuthorizeTypes + end + end +end + +Types::WorkItems::Widgets::LinkedItemsType.prepend_mod |