diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 21:25:58 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-16 21:25:58 +0300 |
commit | a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 (patch) | |
tree | fb69158581673816a8cd895f9d352dcb3c678b1e /app/graphql | |
parent | d16b2e8639e99961de6ddc93909f3bb5c1445ba1 (diff) |
Add latest changes from gitlab-org/gitlab@14-0-stable-eev14.0.0-rc42
Diffstat (limited to 'app/graphql')
46 files changed, 442 insertions, 161 deletions
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index 84941fcde02..8e95bd501ff 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -51,9 +51,8 @@ class GitlabSchema < GraphQL::Schema end def get_type(type_name) - # This is a backwards compatibility hack to work around an accidentally - # released argument typed as EEIterationID - type_name = type_name.gsub(/^EE/, '') if type_name.end_with?('ID') + type_name = Gitlab::GlobalId::Deprecations.apply_to_graphql_name(type_name) + super(type_name) end @@ -162,10 +161,9 @@ class GitlabSchema < GraphQL::Schema end end - # This is a backwards compatibility hack to work around an accidentally - # released argument typed as EE{Type}ID def get_type(type_name) - type_name = type_name.gsub(/^EE/, '') if type_name.end_with?('ID') + type_name = Gitlab::GlobalId::Deprecations.apply_to_graphql_name(type_name) + super(type_name) end end diff --git a/app/graphql/mutations/ci/ci_cd_settings_update.rb b/app/graphql/mutations/ci/ci_cd_settings_update.rb index a484c2438a4..0973e9beae3 100644 --- a/app/graphql/mutations/ci/ci_cd_settings_update.rb +++ b/app/graphql/mutations/ci/ci_cd_settings_update.rb @@ -17,6 +17,10 @@ module Mutations required: false, description: 'Indicates if the latest artifact should be kept for this project.' + argument :job_token_scope_enabled, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Indicates CI job tokens generated in this project have restricted access to resources.' + field :ci_cd_settings, Types::Ci::CiCdSettingType, null: false, diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb new file mode 100644 index 00000000000..8d9a5f15505 --- /dev/null +++ b/app/graphql/mutations/ci/runner/delete.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module Runner + class Delete < BaseMutation + graphql_name 'RunnerDelete' + + authorize :delete_runner + + RunnerID = ::Types::GlobalIDType[::Ci::Runner] + + argument :id, RunnerID, + required: true, + description: 'ID of the runner to delete.' + + def resolve(id:, **runner_attrs) + runner = authorized_find!(id) + + error = authenticate_delete_runner!(runner) + return { errors: [error] } if error + + runner.destroy! + + { errors: runner.errors.full_messages } + end + + def authenticate_delete_runner!(runner) + return if current_user.can_admin_all_resources? + + "Runner #{runner.to_global_id} associated with more than one project" if runner.projects.count > 1 + end + + def find_object(id) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = RunnerID.coerce_isolated_input(id) + + GitlabSchema.find_by_gid(id) + end + end + end + end +end diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb new file mode 100644 index 00000000000..5b61b2ffc0d --- /dev/null +++ b/app/graphql/mutations/ci/runner/update.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module Runner + class Update < BaseMutation + graphql_name 'RunnerUpdate' + + authorize :update_runner + + RunnerID = ::Types::GlobalIDType[::Ci::Runner] + + argument :id, RunnerID, + required: true, + description: 'ID of the runner to update.' + + argument :description, GraphQL::STRING_TYPE, + required: false, + description: 'Description of the runner.' + + argument :maximum_timeout, GraphQL::INT_TYPE, + required: false, + description: 'Maximum timeout (in seconds) for jobs processed by the runner.' + + argument :access_level, ::Types::Ci::RunnerAccessLevelEnum, + required: false, + description: 'Access level of the runner.' + + argument :active, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Indicates the runner is allowed to receive jobs.' + + argument :locked, GraphQL::BOOLEAN_TYPE, required: false, + description: 'Indicates the runner is locked.' + + argument :run_untagged, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Indicates the runner is able to run untagged jobs.' + + argument :tag_list, [GraphQL::STRING_TYPE], required: false, + description: 'Tags associated with the runner.' + + field :runner, + Types::Ci::RunnerType, + null: true, + description: 'The runner after mutation.' + + def resolve(id:, **runner_attrs) + runner = authorized_find!(id) + + unless ::Ci::UpdateRunnerService.new(runner).update(runner_attrs) + return { runner: nil, errors: runner.errors.full_messages } + end + + { runner: runner, errors: [] } + end + + def find_object(id) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = RunnerID.coerce_isolated_input(id) + + GitlabSchema.find_by_gid(id) + end + end + end + end +end diff --git a/app/graphql/mutations/ci/runners_registration_token/reset.rb b/app/graphql/mutations/ci/runners_registration_token/reset.rb new file mode 100644 index 00000000000..e1cdd9a22a5 --- /dev/null +++ b/app/graphql/mutations/ci/runners_registration_token/reset.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +module Mutations + module Ci + module RunnersRegistrationToken + class Reset < BaseMutation + graphql_name 'RunnersRegistrationTokenReset' + + authorize :update_runners_registration_token + + ScopeID = ::GraphQL::ID_TYPE + + argument :type, ::Types::Ci::RunnerTypeEnum, + required: true, + description: 'Scope of the object to reset the token for.' + + argument :id, ScopeID, + required: false, + description: 'ID of the project or group to reset the token for. Omit if resetting instance runner token.' + + field :token, + GraphQL::STRING_TYPE, + null: true, + description: 'The runner token after mutation.' + + def resolve(**args) + { + token: reset_token(**args), + errors: [] + } + end + + private + + def find_object(type:, **args) + id = args[:id] + + case type + when 'group_type' + GitlabSchema.object_from_id(id, expected_type: ::Group) + when 'project_type' + GitlabSchema.object_from_id(id, expected_type: ::Project) + end + end + + def reset_token(type:, **args) + id = args[:id] + + case type + when 'instance_type' + raise Gitlab::Graphql::Errors::ArgumentError, "id must not be specified for '#{type}' scope" if id.present? + + authorize!(:global) + + ApplicationSetting.current.reset_runners_registration_token! + ApplicationSetting.current_without_cache.runners_registration_token + when 'group_type', 'project_type' + project_or_group = authorized_find!(type: type, id: id) + project_or_group.reset_runners_token! + project_or_group.runners_token + end + end + end + end + end +end diff --git a/app/graphql/mutations/commits/create.rb b/app/graphql/mutations/commits/create.rb index 2e06e1ea0c4..f432f679909 100644 --- a/app/graphql/mutations/commits/create.rb +++ b/app/graphql/mutations/commits/create.rb @@ -44,6 +44,11 @@ module Mutations null: true, description: 'The commit after mutation.' + field :content, + [GraphQL::STRING_TYPE], + null: true, + description: 'Contents of the commit.' + authorize :push_code def resolve(project_path:, branch:, message:, actions:, **args) @@ -59,6 +64,7 @@ module Mutations result = ::Files::MultiService.new(project, current_user, attributes).execute { + content: actions.pluck(:content), # rubocop:disable CodeReuse/ActiveRecord because actions is an Array, not a Relation commit: (project.repository.commit(result[:result]) if result[:status] == :success), commit_pipeline_path: UrlHelpers.new.graphql_etag_pipeline_sha_path(result[:result]), errors: Array.wrap(result[:message]) diff --git a/app/graphql/mutations/concerns/mutations/resolves_subscription.rb b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb index e26ae7d228c..ed9fb5fceb0 100644 --- a/app/graphql/mutations/concerns/mutations/resolves_subscription.rb +++ b/app/graphql/mutations/concerns/mutations/resolves_subscription.rb @@ -3,6 +3,7 @@ module Mutations module ResolvesSubscription extend ActiveSupport::Concern + included do argument :subscribed_state, GraphQL::BOOLEAN_TYPE, diff --git a/app/graphql/mutations/issues/set_subscription.rb b/app/graphql/mutations/issues/set_subscription.rb index a04c8f5ba2d..55c9049b7cf 100644 --- a/app/graphql/mutations/issues/set_subscription.rb +++ b/app/graphql/mutations/issues/set_subscription.rb @@ -2,10 +2,32 @@ module Mutations module Issues - class SetSubscription < Base + class SetSubscription < BaseMutation graphql_name 'IssueSetSubscription' include ResolvesSubscription + include Mutations::ResolvesIssuable + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: "The project the issue to mutate is in." + + argument :iid, GraphQL::STRING_TYPE, + required: true, + description: "The IID of the issue to mutate." + + field :issue, + Types::IssueType, + null: true, + description: "The issue after mutation." + + authorize :update_subscription + + private + + def find_object(project_path:, iid:) + resolve_issuable(type: :issue, parent_path: project_path, iid: iid) + end end end end diff --git a/app/graphql/mutations/labels/create.rb b/app/graphql/mutations/labels/create.rb index 4da628d53ea..683d0b44586 100644 --- a/app/graphql/mutations/labels/create.rb +++ b/app/graphql/mutations/labels/create.rb @@ -20,10 +20,6 @@ module Mutations required: false, description: 'Description of the label.' - argument :remove_on_close, GraphQL::BOOLEAN_TYPE, - required: false, - description: copy_field_description(Types::LabelType, :remove_on_close) - argument :color, GraphQL::STRING_TYPE, required: false, default_value: Label::DEFAULT_COLOR, diff --git a/app/graphql/mutations/merge_requests/set_subscription.rb b/app/graphql/mutations/merge_requests/set_subscription.rb index 7d3c40185c9..981daa81c28 100644 --- a/app/graphql/mutations/merge_requests/set_subscription.rb +++ b/app/graphql/mutations/merge_requests/set_subscription.rb @@ -2,10 +2,32 @@ module Mutations module MergeRequests - class SetSubscription < Base + class SetSubscription < BaseMutation graphql_name 'MergeRequestSetSubscription' include ResolvesSubscription + include Mutations::ResolvesIssuable + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: "The project the merge request to mutate is in." + + argument :iid, GraphQL::STRING_TYPE, + required: true, + description: "The IID of the merge request to mutate." + + field :merge_request, + Types::MergeRequestType, + null: true, + description: "The merge request after mutation." + + authorize :update_subscription + + private + + def find_object(project_path:, iid:) + resolve_issuable(type: :merge_request, parent_path: project_path, iid: iid) + end end end end diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb index e9b45294659..d1ad0697acd 100644 --- a/app/graphql/mutations/snippets/create.rb +++ b/app/graphql/mutations/snippets/create.rb @@ -49,7 +49,7 @@ module Mutations process_args_for_params!(args) - service_response = ::Snippets::CreateService.new(project, current_user, args).execute + service_response = ::Snippets::CreateService.new(project: project, current_user: current_user, params: args).execute # Only when the user is not an api user and the operation was successful if !api_user? && service_response.success? diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb index b9b9b13eebb..2e1382e1cb1 100644 --- a/app/graphql/mutations/snippets/update.rb +++ b/app/graphql/mutations/snippets/update.rb @@ -34,7 +34,7 @@ module Mutations process_args_for_params!(args) - service_response = ::Snippets::UpdateService.new(snippet.project, current_user, args).execute(snippet) + service_response = ::Snippets::UpdateService.new(project: snippet.project, current_user: current_user, params: args).execute(snippet) # TODO: DRY this up - From here down, this is all duplicated with Mutations::Snippets::Create#resolve, except for # `snippet.reset`, which is required in order to return the object in its non-dirty, unmodified, database state diff --git a/app/graphql/mutations/todos/mark_all_done.rb b/app/graphql/mutations/todos/mark_all_done.rb index 22a5893d4ec..7dd06cc8293 100644 --- a/app/graphql/mutations/todos/mark_all_done.rb +++ b/app/graphql/mutations/todos/mark_all_done.rb @@ -7,12 +7,6 @@ module Mutations authorize :update_user - field :updated_ids, - [::Types::GlobalIDType[::Todo]], - null: false, - deprecated: { reason: 'Use to-do items', milestone: '13.2' }, - description: 'IDs of the updated to-do items.' - field :todos, [::Types::TodoType], null: false, description: 'Updated to-do items.' @@ -23,7 +17,6 @@ module Mutations updated_ids = mark_all_todos_done { - updated_ids: updated_ids, todos: Todo.id_in(updated_ids), errors: [] } diff --git a/app/graphql/mutations/todos/restore_many.rb b/app/graphql/mutations/todos/restore_many.rb index 41ccbd77aa6..b09c59a3435 100644 --- a/app/graphql/mutations/todos/restore_many.rb +++ b/app/graphql/mutations/todos/restore_many.rb @@ -12,11 +12,6 @@ module Mutations required: true, description: 'The global IDs of the to-do items to restore (a maximum of 50 is supported at once).' - field :updated_ids, [::Types::GlobalIDType[Todo]], - null: false, - description: 'The IDs of the updated to-do items.', - deprecated: { reason: 'Use to-do items', milestone: '13.2' } - field :todos, [::Types::TodoType], null: false, description: 'Updated to-do items.' diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb index 29e66a59a15..dac93b91469 100644 --- a/app/graphql/resolvers/board_list_issues_resolver.rb +++ b/app/graphql/resolvers/board_list_issues_resolver.rb @@ -2,7 +2,7 @@ module Resolvers class BoardListIssuesResolver < BaseResolver - include BoardIssueFilterable + include BoardItemFilterable argument :filters, Types::Boards::BoardIssueInputType, required: false, @@ -13,7 +13,7 @@ module Resolvers alias_method :list, :object def resolve(**args) - filter_params = issue_filters(args[:filters]).merge(board_id: list.board.id, id: list.id) + filter_params = item_filters(args[:filters]).merge(board_id: list.board.id, id: list.id) service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params) offset_pagination(service.execute) diff --git a/app/graphql/resolvers/board_lists_resolver.rb b/app/graphql/resolvers/board_lists_resolver.rb index 0b699006626..4dae3b4a9d1 100644 --- a/app/graphql/resolvers/board_lists_resolver.rb +++ b/app/graphql/resolvers/board_lists_resolver.rb @@ -2,7 +2,7 @@ module Resolvers class BoardListsResolver < BaseResolver - include BoardIssueFilterable + include BoardItemFilterable include Gitlab::Graphql::Authorize::AuthorizeResource include LooksAhead @@ -22,7 +22,7 @@ module Resolvers def resolve_with_lookahead(id: nil, issue_filters: {}) lists = board_lists(id) - context.scoped_set!(:issue_filters, issue_filters(issue_filters)) + context.scoped_set!(:issue_filters, item_filters(issue_filters)) List.preload_preferences_for_user(lists, current_user) if load_preferences? diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb index 710706325cc..3ad1e2780dd 100644 --- a/app/graphql/resolvers/ci/runners_resolver.rb +++ b/app/graphql/resolvers/ci/runners_resolver.rb @@ -17,6 +17,10 @@ module Resolvers required: false, description: 'Filter by tags associated with the runner (comma-separated or array).' + argument :search, GraphQL::STRING_TYPE, + required: false, + description: 'Filter by full token or partial text in description field.' + argument :sort, ::Types::Ci::RunnerSortEnum, required: false, description: 'Sort order of results.' diff --git a/app/graphql/resolvers/concerns/board_issue_filterable.rb b/app/graphql/resolvers/concerns/board_item_filterable.rb index 88de69a3844..1457a02e44f 100644 --- a/app/graphql/resolvers/concerns/board_issue_filterable.rb +++ b/app/graphql/resolvers/concerns/board_item_filterable.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -module BoardIssueFilterable +module BoardItemFilterable extend ActiveSupport::Concern private - def issue_filters(args) + def item_filters(args) filters = args.to_h set_filter_values(filters) @@ -32,4 +32,4 @@ module BoardIssueFilterable end end -::BoardIssueFilterable.prepend_mod_with('Resolvers::BoardIssueFilterable') +::BoardItemFilterable.prepend_mod_with('Resolvers::BoardItemFilterable') diff --git a/app/graphql/resolvers/concerns/time_frame_arguments.rb b/app/graphql/resolvers/concerns/time_frame_arguments.rb index 6cac46a71d2..0ec3c642f29 100644 --- a/app/graphql/resolvers/concerns/time_frame_arguments.rb +++ b/app/graphql/resolvers/concerns/time_frame_arguments.rb @@ -39,4 +39,12 @@ module TimeFrameArguments raise Gitlab::Graphql::Errors::ArgumentError, error_message end end + + def transform_timeframe_parameters(args) + if args[:timeframe] + args[:timeframe].transform_keys { |k| :"#{k}_date" } + else + args.slice(:start_date, :end_date) + end + end end diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb index c94e3d9e1d8..1241b41501d 100644 --- a/app/graphql/resolvers/milestones_resolver.rb +++ b/app/graphql/resolvers/milestones_resolver.rb @@ -44,15 +44,7 @@ module Resolvers title: args[:title], search_title: args[:search_title], containing_date: args[:containing_date] - }.merge!(timeframe_parameters(args)).merge!(parent_id_parameters(args)) - end - - def timeframe_parameters(args) - if args[:timeframe] - args[:timeframe].transform_keys { |k| :"#{k}_date" } - else - args.slice(:start_date, :end_date) - end + }.merge!(transform_timeframe_parameters(args)).merge!(parent_id_parameters(args)) end def parent diff --git a/app/graphql/resolvers/projects/services_resolver.rb b/app/graphql/resolvers/projects/services_resolver.rb index db3037ec591..3674aa97e1f 100644 --- a/app/graphql/resolvers/projects/services_resolver.rb +++ b/app/graphql/resolvers/projects/services_resolver.rb @@ -12,19 +12,19 @@ module Resolvers argument :active, GraphQL::BOOLEAN_TYPE, required: false, - description: 'Indicates if the service is active.' + description: 'Indicates if the integration is active.' argument :type, Types::Projects::ServiceTypeEnum, required: false, - description: 'Class name of the service.' + description: 'Type of integration.' alias_method :project, :object def resolve(active: nil, type: nil) - servs = project.integrations - servs = servs.by_active_flag(active) unless active.nil? - servs = servs.by_type(type) unless type.blank? - servs + items = project.integrations + items = items.by_active_flag(active) unless active.nil? + items = items.by_type(type) unless type.blank? + items end end end diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb index 11d18a0a080..665ec796cd3 100644 --- a/app/graphql/resolvers/projects_resolver.rb +++ b/app/graphql/resolvers/projects_resolver.rb @@ -24,6 +24,10 @@ module Resolvers required: false, description: 'Sort order of results.' + argument :topics, type: [GraphQL::STRING_TYPE], + required: false, + description: 'Filters projects by topics.' + def resolve(**args) ProjectsFinder .new(current_user: current_user, params: project_finder_params(args), project_ids_relation: parse_gids(args[:ids])) @@ -38,7 +42,8 @@ module Resolvers non_public: params[:membership], search: params[:search], search_namespaces: params[:search_namespaces], - sort: params[:sort] + sort: params[:sort], + topic: params[:topics] }.compact end diff --git a/app/graphql/resolvers/timelog_resolver.rb b/app/graphql/resolvers/timelog_resolver.rb index aebd04259ee..8ac30c4cb5d 100644 --- a/app/graphql/resolvers/timelog_resolver.rb +++ b/app/graphql/resolvers/timelog_resolver.rb @@ -7,106 +7,88 @@ module Resolvers type ::Types::TimelogType.connection_type, null: false argument :start_date, Types::TimeType, - required: false, - description: 'List time logs within a date range where the logged date is equal to or after startDate.' + required: false, + description: 'List time logs within a date range where the logged date is equal to or after startDate.' argument :end_date, Types::TimeType, - required: false, - description: 'List time logs within a date range where the logged date is equal to or before endDate.' + required: false, + description: 'List time logs within a date range where the logged date is equal to or before endDate.' argument :start_time, Types::TimeType, - required: false, - description: 'List time-logs within a time range where the logged time is equal to or after startTime.' + required: false, + description: 'List time-logs within a time range where the logged time is equal to or after startTime.' argument :end_time, Types::TimeType, - required: false, - description: 'List time-logs within a time range where the logged time is equal to or before endTime.' + required: false, + description: 'List time-logs within a time range where the logged time is equal to or before endTime.' def resolve_with_lookahead(**args) - return Timelog.none unless timelogs_available_for_user? + build_timelogs - validate_params_presence!(args) - transformed_args = transform_args(args) - validate_time_difference!(transformed_args) + if args.any? + validate_args!(args) + build_parsed_args(args) + validate_time_difference! + apply_time_filter + end - find_timelogs(transformed_args) + apply_lookahead(timelogs) end private + attr_reader :parsed_args, :timelogs + def preloads { note: [:note] } end - def find_timelogs(args) - apply_lookahead(group.timelogs(args[:start_time], args[:end_time])) + def validate_args!(args) + if args[:start_time] && args[:start_date] + raise_argument_error('Provide either a start date or time, but not both') + elsif args[:end_time] && args[:end_date] + raise_argument_error('Provide either an end date or time, but not both') + end end - def timelogs_available_for_user? - group&.user_can_access_group_timelogs?(context[:current_user]) - end + def build_parsed_args(args) + if times_provided?(args) + @parsed_args = args + else + @parsed_args = args.except(:start_date, :end_date) - def validate_params_presence!(args) - message = case time_params_count(args) - when 0 - 'Start and End arguments must be present' - when 1 - 'Both Start and End arguments must be present' - when 2 - validate_duplicated_args(args) - when 3 || 4 - 'Only Time or Date arguments must be present' - end - - raise_argument_error(message) if message + @parsed_args[:start_time] = args[:start_date].beginning_of_day if args[:start_date] + @parsed_args[:end_time] = args[:end_date].end_of_day if args[:end_date] + end end - def validate_time_difference!(args) - message = if args[:end_time] < args[:start_time] - 'Start argument must be before End argument' - elsif args[:end_time] - args[:start_time] > 60.days - 'The time range period cannot contain more than 60 days' - end - - raise_argument_error(message) if message + def times_provided?(args) + args[:start_time] && args[:end_time] end - def transform_args(args) - return args if args.keys == [:start_time, :end_time] + def validate_time_difference! + return unless end_time_before_start_time? - time_args = args.except(:start_date, :end_date) - - if time_args.empty? - time_args[:start_time] = args[:start_date].beginning_of_day - time_args[:end_time] = args[:end_date].end_of_day - elsif time_args.key?(:start_time) - time_args[:end_time] = args[:end_date].end_of_day - elsif time_args.key?(:end_time) - time_args[:start_time] = args[:start_date].beginning_of_day - end + raise_argument_error('Start argument must be before End argument') + end - time_args + def end_time_before_start_time? + times_provided?(parsed_args) && parsed_args[:end_time] < parsed_args[:start_time] end - def time_params_count(args) - [:start_time, :end_time, :start_date, :end_date].count { |param| args.key?(param) } + def build_timelogs + @timelogs = Timelog.in_group(object) end - def validate_duplicated_args(args) - if args.key?(:start_time) && args.key?(:start_date) || - args.key?(:end_time) && args.key?(:end_date) - 'Both Start and End arguments must be present' - end + def apply_time_filter + @timelogs = timelogs.at_or_after(parsed_args[:start_time]) if parsed_args[:start_time] + @timelogs = timelogs.at_or_before(parsed_args[:end_time]) if parsed_args[:end_time] end def raise_argument_error(message) raise Gitlab::Graphql::Errors::ArgumentError, message end - - def group - @group ||= object.respond_to?(:sync) ? object.sync : object - end end end diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index 7ef1cbddbd9..d70236f16f9 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -2,7 +2,19 @@ module Types class BaseEnum < GraphQL::Schema::Enum - extend GitlabStyleDeprecations + class CustomValue < GraphQL::Schema::EnumValue + include ::GitlabStyleDeprecations + + attr_reader :deprecation + + def initialize(name, desc = nil, **kwargs) + @deprecation = gitlab_deprecation(kwargs) + + super(name, desc, **kwargs) + end + end + + enum_value_class(CustomValue) class << self # Registers enum definition by the given DeclarativeEnum module @@ -41,7 +53,6 @@ module Types def value(*args, **kwargs, &block) enum[args[0].downcase] = kwargs[:value] || args[0] - gitlab_deprecation(kwargs) super(*args, **kwargs, &block) end diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb index b34a91446a2..f90c75454ba 100644 --- a/app/graphql/types/ci/ci_cd_setting_type.rb +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -16,6 +16,9 @@ module Types field :keep_latest_artifact, GraphQL::BOOLEAN_TYPE, null: true, description: 'Whether to keep the latest builds artifacts.', method: :keep_latest_artifacts_available? + field :job_token_scope_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates CI job tokens generated in this project have restricted access to resources.', + method: :job_token_scope_enabled? field :project, Types::ProjectType, null: true, description: 'Project the CI/CD settings belong to.' end diff --git a/app/graphql/types/ci/runner_sort_enum.rb b/app/graphql/types/ci/runner_sort_enum.rb index 550e870316a..95ec1867fea 100644 --- a/app/graphql/types/ci/runner_sort_enum.rb +++ b/app/graphql/types/ci/runner_sort_enum.rb @@ -7,7 +7,9 @@ module Types description 'Values for sorting runners' value 'CONTACTED_ASC', 'Ordered by contacted_at in ascending order.', value: :contacted_asc - value 'CREATED_DESC', 'Ordered by created_date in descending order.', value: :created_date + value 'CONTACTED_DESC', 'Ordered by contacted_at in descending order.', value: :contacted_desc + value 'CREATED_ASC', 'Ordered by created_at in ascending order.', value: :created_at_asc + value 'CREATED_DESC', 'Ordered by created_at in descending order.', value: :created_at_desc end end end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 3abed7289d5..837d91ef765 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -40,3 +40,5 @@ module Types end end end + +Types::Ci::RunnerType.prepend_mod_with('Types::Ci::RunnerType') diff --git a/app/graphql/types/ci/runner_type_enum.rb b/app/graphql/types/ci/runner_type_enum.rb index f771635f4ed..12e87906179 100644 --- a/app/graphql/types/ci/runner_type_enum.rb +++ b/app/graphql/types/ci/runner_type_enum.rb @@ -5,10 +5,10 @@ module Types class RunnerTypeEnum < BaseEnum graphql_name 'CiRunnerType' - ::Ci::Runner.runner_types.keys.each do |type| - value type.upcase, - description: "A runner that is #{type.tr('_', ' ')}.", - value: type + ::Ci::Runner::AVAILABLE_TYPES.each do |runner_type| + value runner_type.upcase, + description: "A runner that is #{runner_type.tr('_', ' ')}.", + value: runner_type end end end diff --git a/app/graphql/types/deprecated_mutations.rb b/app/graphql/types/deprecated_mutations.rb index a4336fa3ef3..49bad56b6f9 100644 --- a/app/graphql/types/deprecated_mutations.rb +++ b/app/graphql/types/deprecated_mutations.rb @@ -5,15 +5,7 @@ module Types extend ActiveSupport::Concern prepended do - mount_aliased_mutation 'AddAwardEmoji', - Mutations::AwardEmojis::Add, - deprecated: { reason: 'Use awardEmojiAdd', milestone: '13.2' } - mount_aliased_mutation 'RemoveAwardEmoji', - Mutations::AwardEmojis::Remove, - deprecated: { reason: 'Use awardEmojiRemove', milestone: '13.2' } - mount_aliased_mutation 'ToggleAwardEmoji', - Mutations::AwardEmojis::Toggle, - deprecated: { reason: 'Use awardEmojiToggle', milestone: '13.2' } + # placeholder for any FOSS mutations to be deprecated end end end diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb index 79061df7282..c44c268b43f 100644 --- a/app/graphql/types/global_id_type.rb +++ b/app/graphql/types/global_id_type.rb @@ -52,11 +52,20 @@ module Types @id_types ||= {} @id_types[model_class] ||= Class.new(self) do - graphql_name "#{model_class.name.gsub(/::/, '')}ID" - description <<~MD + model_name = model_class.name + + graphql_name model_name_to_graphql_name(model_name) + description <<~MD.strip A `#{graphql_name}` is a global ID. It is encoded as a string. - An example `#{graphql_name}` is: `"#{::Gitlab::GlobalId.build(model_name: model_class.name, id: 1)}"`. + An example `#{graphql_name}` is: `"#{::Gitlab::GlobalId.build(model_name: model_name, id: 1)}"`. + #{ + if deprecation = Gitlab::GlobalId::Deprecations.deprecation_by(model_name) + 'The older format `"' + + ::Gitlab::GlobalId.build(model_name: deprecation.old_model_name, id: 1).to_s + + '"` was deprecated in ' + deprecation.milestone + '.' + end} + MD define_singleton_method(:to_s) do @@ -69,7 +78,7 @@ module Types define_singleton_method(:as) do |new_name| if @renamed && graphql_name != new_name - raise "Conflicting names for ID of #{model_class.name}: " \ + raise "Conflicting names for ID of #{model_name}: " \ "#{graphql_name} and #{new_name}" end @@ -79,11 +88,11 @@ module Types end define_singleton_method(:coerce_result) do |gid, ctx| - global_id = ::Gitlab::GlobalId.as_global_id(gid, model_name: model_class.name) + global_id = ::Gitlab::GlobalId.as_global_id(gid, model_name: model_name) next global_id.to_s if suitable?(global_id) - raise GraphQL::CoercionError, "Expected a #{model_class.name} ID, got #{global_id}" + raise GraphQL::CoercionError, "Expected a #{model_name} ID, got #{global_id}" end define_singleton_method(:suitable?) do |gid| @@ -97,9 +106,13 @@ module Types gid = super(string, ctx) next gid if suitable?(gid) - raise GraphQL::CoercionError, "#{string.inspect} does not represent an instance of #{model_class.name}" + raise GraphQL::CoercionError, "#{string.inspect} does not represent an instance of #{model_name}" end end end + + def self.model_name_to_graphql_name(model_name) + "#{model_name.gsub(/::/, '')}ID" + end end end diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index cb6b0312aa3..4e8718a80da 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -23,7 +23,5 @@ module Types description: 'When this label was created.' field :updated_at, Types::TimeType, null: false, description: 'When this label was last updated.' - field :remove_on_close, GraphQL::BOOLEAN_TYPE, null: false, - description: 'Whether the label should be removed from an issue when the issue is closed.' end end diff --git a/app/graphql/types/member_interface.rb b/app/graphql/types/member_interface.rb index 1c7257487d9..6a21e51fe28 100644 --- a/app/graphql/types/member_interface.rb +++ b/app/graphql/types/member_interface.rb @@ -22,7 +22,7 @@ module Types field :expires_at, Types::TimeType, null: true, description: 'Date and time the membership expires.' - field :user, Types::UserType, null: false, + field :user, Types::UserType, null: true, description: 'User that is associated with the member object.' definition_methods do diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 4eeeaa4f5d0..338b70bb0c6 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -82,7 +82,11 @@ module Types field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true, description: 'Indicates if the project settings will lead to source branch deletion after merge.' field :merge_status, GraphQL::STRING_TYPE, method: :public_merge_status, null: true, - description: 'Status of the merge request.' + description: 'Status of the merge request.', + deprecated: { reason: :renamed, replacement: 'MergeRequest.mergeStatusEnum', milestone: '14.0' } + field :merge_status_enum, ::Types::MergeRequests::MergeStatusEnum, + method: :public_merge_status, null: true, + description: 'Merge status of the merge request.' field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true, description: 'Commit SHA of the merge request if merge is in progress.' field :merge_error, GraphQL::STRING_TYPE, null: true, @@ -158,6 +162,10 @@ module Types description: 'Time estimate of the merge request.' field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the merge request.' + field :human_time_estimate, GraphQL::STRING_TYPE, null: true, + description: 'Human-readable time estimate of the merge request.' + field :human_total_time_spent, GraphQL::STRING_TYPE, null: true, + description: 'Human-readable total time reported as spent on the merge request.' field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference, description: 'Internal reference of the merge request. Returned in shortened format by default.' do argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, diff --git a/app/graphql/types/merge_requests/merge_status_enum.rb b/app/graphql/types/merge_requests/merge_status_enum.rb new file mode 100644 index 00000000000..bb3e0f1a0c0 --- /dev/null +++ b/app/graphql/types/merge_requests/merge_status_enum.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class MergeStatusEnum < BaseEnum + graphql_name 'MergeStatus' + description 'Representation of whether a GitLab merge request can be merged.' + + value 'UNCHECKED', + value: 'unchecked', + description: 'Merge status has not been checked.' + value 'CHECKING', + value: 'checking', + description: 'Currently checking for mergeability.' + value 'CAN_BE_MERGED', + value: 'can_be_merged', + description: 'There are no conflicts between the source and target branches.' + value 'CANNOT_BE_MERGED', + value: 'cannot_be_merged', + description: 'There are conflicts between the source and target branches.' + value 'CANNOT_BE_MERGED_RECHECK', + value: 'cannot_be_merged_recheck', + description: 'Currently unchecked. The previous state was `CANNOT_BE_MERGED`.' + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 54a06ed5342..6b1146f8f09 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -99,6 +99,9 @@ module Types mount_mutation Mutations::Ci::CiCdSettingsUpdate mount_mutation Mutations::Ci::Job::Play mount_mutation Mutations::Ci::Job::Retry + mount_mutation Mutations::Ci::Runner::Update, feature_flag: :runner_graphql_query + mount_mutation Mutations::Ci::Runner::Delete, feature_flag: :runner_graphql_query + mount_mutation Mutations::Ci::RunnersRegistrationToken::Reset, feature_flag: :runner_graphql_query mount_mutation Mutations::Namespace::PackageSettings::Update mount_mutation Mutations::UserCallouts::Create end diff --git a/app/graphql/types/packages/metadata_type.rb b/app/graphql/types/packages/metadata_type.rb index 94880cb9b22..3b2257547b7 100644 --- a/app/graphql/types/packages/metadata_type.rb +++ b/app/graphql/types/packages/metadata_type.rb @@ -6,7 +6,7 @@ module Types graphql_name 'PackageMetadata' description 'Represents metadata associated with a Package' - possible_types ::Types::Packages::Composer::MetadatumType, ::Types::Packages::Conan::MetadatumType, ::Types::Packages::Maven::MetadatumType, ::Types::Packages::Nuget::MetadatumType + possible_types ::Types::Packages::Composer::MetadatumType, ::Types::Packages::Conan::MetadatumType, ::Types::Packages::Maven::MetadatumType, ::Types::Packages::Nuget::MetadatumType, ::Types::Packages::Pypi::MetadatumType def self.resolve_type(object, context) case object @@ -18,6 +18,8 @@ module Types ::Types::Packages::Maven::MetadatumType when ::Packages::Nuget::Metadatum ::Types::Packages::Nuget::MetadatumType + when ::Packages::Pypi::Metadatum + ::Types::Packages::Pypi::MetadatumType else # NOTE: This method must be kept in sync with `PackageWithoutVersionsType#metadata`, # which must never produce data that this discriminator cannot handle. diff --git a/app/graphql/types/packages/package_group_sort_enum.rb b/app/graphql/types/packages/package_group_sort_enum.rb index 70fb27ec0db..28a1bf85911 100644 --- a/app/graphql/types/packages/package_group_sort_enum.rb +++ b/app/graphql/types/packages/package_group_sort_enum.rb @@ -6,10 +6,8 @@ module Types graphql_name 'PackageGroupSort' description 'Values for sorting group packages' - # The following enums are not available till we enable the new Arel node: - # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58657#note_552632305 - # value 'PROJECT_PATH_DESC', 'Project by descending order.', value: :project_path_desc - # value 'PROJECT_PATH_ASC', 'Project by ascending order.', value: :project_path_asc + value 'PROJECT_PATH_DESC', 'Ordered by project path in descending order.', value: :project_path_desc + value 'PROJECT_PATH_ASC', 'Ordered by project path in ascending order.', value: :project_path_asc end end end diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index b349b655fa5..ee6785e3555 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -49,6 +49,8 @@ module Types object.maven_metadatum when 'nuget' object.nuget_metadatum + when 'pypi' + object.pypi_metadatum else nil end diff --git a/app/graphql/types/packages/pypi/metadatum_type.rb b/app/graphql/types/packages/pypi/metadatum_type.rb new file mode 100644 index 00000000000..031d3572197 --- /dev/null +++ b/app/graphql/types/packages/pypi/metadatum_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + module Packages + module Pypi + class MetadatumType < BaseObject + graphql_name 'PypiMetadata' + description 'Pypi metadata' + + authorize :read_package + + field :id, ::Types::GlobalIDType[::Packages::Pypi::Metadatum], null: false, description: 'ID of the metadatum.' + field :required_python, GraphQL::STRING_TYPE, null: true, description: 'Required Python version of the Pypi package.' + end + end + end +end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index a2852588e89..55dc73d898d 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -387,6 +387,10 @@ module Types ::Security::CiConfiguration::SastParserService.new(object).configuration end + def tag_list + object.topic_list + end + private def project diff --git a/app/graphql/types/projects/service_type.rb b/app/graphql/types/projects/service_type.rb index 9ce325c4655..6f0dcd44cad 100644 --- a/app/graphql/types/projects/service_type.rb +++ b/app/graphql/types/projects/service_type.rb @@ -15,7 +15,7 @@ module Types definition_methods do def resolve_type(object, context) - if object.is_a?(::JiraService) + if object.is_a?(::Integrations::Jira) Types::Projects::Services::JiraServiceType else Types::Projects::Services::BaseServiceType diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb index 0a57cd48df4..9948fa8bb69 100644 --- a/app/graphql/types/projects/service_type_enum.rb +++ b/app/graphql/types/projects/service_type_enum.rb @@ -5,8 +5,8 @@ module Types class ServiceTypeEnum < BaseEnum graphql_name 'ServiceType' - ::Integration.available_services_types(include_dev: false).each do |service_type| - value service_type.underscore.upcase, value: service_type, description: "#{service_type} type" + ::Integration.available_services_types(include_dev: false).each do |type| + value type.underscore.upcase, value: type, description: "#{type} type" end end end diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 2f79ec48c04..34357ead048 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -61,12 +61,6 @@ module Types description: 'Raw URL of the snippet.', null: false - field :blob, type: Types::Snippets::BlobType, - description: 'Snippet blob.', - calls_gitaly: true, - null: false, - deprecated: { reason: 'Use `blobs`', milestone: '13.3' } - field :blobs, type: Types::Snippets::BlobType.connection_type, description: 'Snippet blobs.', calls_gitaly: true, diff --git a/app/graphql/types/snippets/blob_action_enum.rb b/app/graphql/types/snippets/blob_action_enum.rb index e3f89920f16..0defd521acb 100644 --- a/app/graphql/types/snippets/blob_action_enum.rb +++ b/app/graphql/types/snippets/blob_action_enum.rb @@ -6,10 +6,10 @@ module Types graphql_name 'SnippetBlobActionEnum' description 'Type of a snippet blob input action' - value 'create', value: :create - value 'update', value: :update - value 'delete', value: :delete - value 'move', value: :move + value 'create', description: 'Create a snippet blob.', value: :create + value 'update', description: 'Update a snippet blob.', value: :update + value 'delete', description: 'Delete a snippet blob.', value: :delete + value 'move', description: 'Move a snippet blob.', value: :move end end end diff --git a/app/graphql/types/snippets/visibility_scopes_enum.rb b/app/graphql/types/snippets/visibility_scopes_enum.rb index 5488e05b95d..ddcc005eaf2 100644 --- a/app/graphql/types/snippets/visibility_scopes_enum.rb +++ b/app/graphql/types/snippets/visibility_scopes_enum.rb @@ -3,9 +3,9 @@ module Types module Snippets class VisibilityScopesEnum < BaseEnum - value 'private', value: 'are_private' - value 'internal', value: 'are_internal' - value 'public', value: 'are_public' + value 'private', description: 'The snippet is visible only to the snippet creator.', value: 'are_private' + value 'internal', description: 'The snippet is visible for any logged in user except external users.', value: 'are_internal' + value 'public', description: 'The snippet can be accessed without any authentication.', value: 'are_public' end end end diff --git a/app/graphql/types/timelog_type.rb b/app/graphql/types/timelog_type.rb index 99a619f1b1d..925a522629e 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' - authorize :read_group_timelogs + authorize :read_issue field :spent_at, Types::TimeType, |