diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-19 15:57:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-19 15:57:54 +0300 |
commit | 419c53ec62de6e97a517abd5fdd4cbde3a942a34 (patch) | |
tree | 1f43a548b46bca8a5fb8fe0c31cef1883d49c5b6 /app/graphql | |
parent | 1da20d9135b3ad9e75e65b028bffc921aaf8deb7 (diff) |
Add latest changes from gitlab-org/gitlab@16-5-stable-eev16.5.0-rc42
Diffstat (limited to 'app/graphql')
70 files changed, 542 insertions, 115 deletions
diff --git a/app/graphql/mutations/achievements/update_user_achievement_priorities.rb b/app/graphql/mutations/achievements/update_user_achievement_priorities.rb new file mode 100644 index 00000000000..077b4810fdc --- /dev/null +++ b/app/graphql/mutations/achievements/update_user_achievement_priorities.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Mutations + module Achievements + class UpdateUserAchievementPriorities < BaseMutation + graphql_name 'UserAchievementPrioritiesUpdate' + + field :user_achievements, + [::Types::Achievements::UserAchievementType], + null: false, + description: 'Updated user achievements.' + + argument :user_achievement_ids, + [::Types::GlobalIDType[::Achievements::UserAchievement]], + required: true, + description: 'Global IDs of the user achievements being prioritized, ' \ + 'ordered from highest to lowest priority.' + + def resolve(args) + user_achievements = args.delete(:user_achievement_ids).map { |id| find_object(id) } + + user_achievements.each do |user_achievement| + unless Ability.allowed?(current_user, :update_owned_user_achievement, user_achievement) + raise_resource_not_available_error! + end + end + + result = ::Achievements::UpdateUserAchievementPrioritiesService.new(current_user, user_achievements).execute + { user_achievements: result.payload, errors: result.errors } + end + + def find_object(id) + ::Gitlab::Graphql::Lazy.force(GitlabSchema.object_from_id(id, expected_type: ::Achievements::UserAchievement)) + end + end + end +end diff --git a/app/graphql/mutations/ci/job/retry.rb b/app/graphql/mutations/ci/job/retry.rb index bfb9b902cc5..5ccc33de33e 100644 --- a/app/graphql/mutations/ci/job/retry.rb +++ b/app/graphql/mutations/ci/job/retry.rb @@ -6,6 +6,12 @@ module Mutations class Retry < Base graphql_name 'JobRetry' + JobID = ::Types::GlobalIDType[::Ci::Processable] + + argument :id, JobID, + required: true, + description: 'ID of the job to mutate.' + field :job, Types::Ci::JobType, null: true, diff --git a/app/graphql/mutations/merge_requests/accept.rb b/app/graphql/mutations/merge_requests/accept.rb index 64572091379..220ebea22c7 100644 --- a/app/graphql/mutations/merge_requests/accept.rb +++ b/app/graphql/mutations/merge_requests/accept.rb @@ -7,7 +7,7 @@ module Mutations authorize :accept_merge_request description <<~DESC Accepts a merge request. - When accepted, the source branch will be merged into the target branch, either + When accepted, the source branch will be scheduled to merge into the target branch, either immediately if possible, or using one of the automatic merge strategies. DESC @@ -59,7 +59,7 @@ module Mutations service = AutoMergeService.new(project, current_user, merge_params) service.execute(merge_request, merge_params[:auto_merge_strategy]) else - merge_service.execute(merge_request) + merge_request.merge_async(current_user.id, merge_params) end { diff --git a/app/graphql/mutations/packages/protection/rule/create.rb b/app/graphql/mutations/packages/protection/rule/create.rb new file mode 100644 index 00000000000..36eaec334d6 --- /dev/null +++ b/app/graphql/mutations/packages/protection/rule/create.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module Mutations + module Packages + module Protection + module Rule + class Create < ::Mutations::BaseMutation + graphql_name 'CreatePackagesProtectionRule' + description 'Creates a protection rule to restrict access to project packages. ' \ + 'Available only when feature flag `packages_protected_packages` is enabled.' + + include FindsProject + + authorize :admin_package + + argument :project_path, + GraphQL::Types::ID, + required: true, + description: 'Full path of the project where a protection rule is located.' + + argument :package_name_pattern, + GraphQL::Types::String, + required: true, + description: + 'Package name protected by the protection rule. For example `@my-scope/my-package-*`. ' \ + 'Wildcard character `*` allowed.' + + argument :package_type, + Types::Packages::Protection::RulePackageTypeEnum, + required: true, + description: 'Package type protected by the protection rule. For example `NPM`.' + + argument :push_protected_up_to_access_level, + Types::Packages::Protection::RuleAccessLevelEnum, + required: true, + description: + 'Max GitLab access level unable to push a package. For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + + field :package_protection_rule, + Types::Packages::Protection::RuleType, + null: true, + description: 'Packages protection rule after mutation.' + + def resolve(project_path:, **kwargs) + project = authorized_find!(project_path) + + if Feature.disabled?(:packages_protected_packages, project) + raise_resource_not_available_error!("'packages_protected_packages' feature flag is disabled") + end + + response = ::Packages::Protection::CreateRuleService.new(project: project, current_user: current_user, + params: kwargs).execute + + { package_protection_rule: response.payload[:package_protection_rule], errors: response.errors } + end + end + end + end + end +end diff --git a/app/graphql/mutations/users/set_namespace_commit_email.rb b/app/graphql/mutations/users/set_namespace_commit_email.rb index 72ef0635bb3..db1c33595f2 100644 --- a/app/graphql/mutations/users/set_namespace_commit_email.rb +++ b/app/graphql/mutations/users/set_namespace_commit_email.rb @@ -20,7 +20,7 @@ module Mutations null: true, description: 'User namespace commit email after mutation.' - authorize :read_namespace + authorize :read_namespace_via_membership def resolve(args) namespace = authorized_find!(args[:namespace_id]) diff --git a/app/graphql/mutations/work_items/linked_items/add.rb b/app/graphql/mutations/work_items/linked_items/add.rb index e0c17a61205..4029d17d4ac 100644 --- a/app/graphql/mutations/work_items/linked_items/add.rb +++ b/app/graphql/mutations/work_items/linked_items/add.rb @@ -16,8 +16,6 @@ module Mutations 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) diff --git a/app/graphql/mutations/work_items/linked_items/base.rb b/app/graphql/mutations/work_items/linked_items/base.rb index a1d9bced930..8a6201ffdf7 100644 --- a/app/graphql/mutations/work_items/linked_items/base.rb +++ b/app/graphql/mutations/work_items/linked_items/base.rb @@ -5,8 +5,7 @@ module Mutations 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 + MAX_WORK_ITEMS = 10 argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.' @@ -33,7 +32,7 @@ module Mutations 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? + raise_resource_not_available_error! unless work_item.resource_parent.linked_work_items_feature_flag_enabled? service_response = update_links(work_item, args) diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb index f22e9bcf393..228a9e52355 100644 --- a/app/graphql/mutations/work_items/update.rb +++ b/app/graphql/mutations/work_items/update.rb @@ -10,7 +10,7 @@ module Mutations include Mutations::WorkItems::UpdateArguments include Mutations::WorkItems::Widgetable - authorize :update_work_item + authorize :read_work_item field :work_item, Types::WorkItemType, null: true, @@ -22,11 +22,13 @@ module Mutations work_item = authorized_find!(id: id) widget_params = extract_widget_params!(work_item.work_item_type, attributes) - interpret_quick_actions!(work_item, current_user, widget_params, attributes) + # Only checks permissions for base attributes because widgets define their own permissions independently + raise_resource_not_available_error! unless attributes.empty? || can_update?(work_item) + update_result = ::WorkItems::UpdateService.new( - container: work_item.project, + container: work_item.resource_parent, current_user: current_user, params: attributes, widget_params: widget_params, @@ -62,6 +64,10 @@ module Mutations widget_params.merge!(parsed_params[:widgets]) attributes.merge!(parsed_params[:common]) end + + def can_update?(work_item) + current_user.can?(:update_work_item, work_item) + end end end end diff --git a/app/graphql/resolvers/achievements/user_achievements_for_user_resolver.rb b/app/graphql/resolvers/achievements/user_achievements_for_user_resolver.rb new file mode 100644 index 00000000000..673babcf14a --- /dev/null +++ b/app/graphql/resolvers/achievements/user_achievements_for_user_resolver.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Resolvers + module Achievements + # rubocop:disable Graphql/ResolverType -- the type is inherited from the parent class + class UserAchievementsForUserResolver < UserAchievementsResolver + def resolve_with_lookahead + super.order_by_priority_asc + end + end + # rubocop:enable Graphql/ResolverType + end +end diff --git a/app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb b/app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb index b5a19d38b9c..0c9607d9413 100644 --- a/app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb +++ b/app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb @@ -7,7 +7,7 @@ module Resolvers class MeasurementsResolver < BaseResolver include Gitlab::Graphql::Authorize::AuthorizeResource - type Types::Admin::Analytics::UsageTrends::MeasurementType, null: true + type Types::Admin::Analytics::UsageTrends::MeasurementType.connection_type, null: true argument :identifier, Types::Admin::Analytics::UsageTrends::MeasurementIdentifierEnum, required: true, diff --git a/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb index 8128023aecb..768265752d5 100644 --- a/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb +++ b/app/graphql/resolvers/analytics/cycle_analytics/base_issue_resolver.rb @@ -48,3 +48,5 @@ module Resolvers end end end + +Resolvers::Analytics::CycleAnalytics::BaseIssueResolver.prepend_mod diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb index 6f847221f1b..17db91a685f 100644 --- a/app/graphql/resolvers/base_resolver.rb +++ b/app/graphql/resolvers/base_resolver.rb @@ -11,26 +11,25 @@ module Resolvers @requires_argument = true end + def self.requires_argument? + !!@requires_argument + end + def self.calls_gitaly! @calls_gitaly = true end + def self.calls_gitaly? + !!@calls_gitaly + end + # This is a flag to allow us to use `complexity_multiplier` to compute complexity for connection # fields(see BaseField#connection_complexity_multiplier) in resolvers that do external connection pagination, - # thus disabling the default `connection` option(see self.field_options method above). + # thus disabling the default `connection` option. def self.calculate_ext_conn_complexity false end - def self.field_options - extra_options = { - requires_argument: @requires_argument, - calls_gitaly: @calls_gitaly - }.compact - - super.merge(extra_options) - end - def self.singular_type return unless type @@ -63,8 +62,13 @@ module Resolvers type parent.singular_type, null: true def ready?(**args) - ready, early_return = super - [ready, select_result(early_return)] + value = super + + if value.is_a?(Array) + [value[0], select_result(value[1])] + else + value + end end def resolve(**args) diff --git a/app/graphql/resolvers/blobs_resolver.rb b/app/graphql/resolvers/blobs_resolver.rb index 546eeb76ff5..27a15381b43 100644 --- a/app/graphql/resolvers/blobs_resolver.rb +++ b/app/graphql/resolvers/blobs_resolver.rb @@ -36,7 +36,7 @@ module Resolvers ref ||= repository.root_ref validate_ref(ref) - ref = ExtractsRef.qualify_ref(ref, ref_type) + ref = ExtractsRef::RefExtractor.qualify_ref(ref, ref_type) repository.blobs_at(paths.map { |path| [ref, path] }).tap do |blobs| blobs.each do |blob| diff --git a/app/graphql/resolvers/ci/config_resolver.rb b/app/graphql/resolvers/ci/config_resolver.rb index ec6ede58cf5..8c85a6aebea 100644 --- a/app/graphql/resolvers/ci/config_resolver.rb +++ b/app/graphql/resolvers/ci/config_resolver.rb @@ -30,11 +30,20 @@ module Resolvers required: false, description: 'Run pipeline creation simulation, or only do static check.' - def resolve(project_path:, content:, sha: nil, dry_run: false) + argument :skip_verify_project_sha, GraphQL::Types::Boolean, + required: false, + alpha: { milestone: '16.5' }, + description: "If the provided `sha` is found in the project's repository but is not " \ + "associated with a Git reference (a detached commit), the verification fails and a " \ + "validation error is returned. Otherwise, verification passes, even if the `sha` is " \ + "invalid. Set to `true` to skip this verification process." + + def resolve(project_path:, content:, sha: nil, dry_run: false, skip_verify_project_sha: false) project = authorized_find!(project_path: project_path) result = ::Gitlab::Ci::Lint - .new(project: project, current_user: context[:current_user], sha: sha) + .new(project: project, current_user: context[:current_user], sha: sha, + verify_project_sha: !skip_verify_project_sha) .validate(content, dry_run: dry_run) response(result) diff --git a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb index 0b9422db2a9..313d71aa345 100644 --- a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb +++ b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb @@ -3,7 +3,7 @@ module Resolvers module Clusters class AgentTokensResolver < BaseResolver - type Types::Clusters::AgentTokenType, null: true + type Types::Clusters::AgentTokenType.connection_type, null: true alias_method :agent, :object diff --git a/app/graphql/resolvers/concerns/caching_array_resolver.rb b/app/graphql/resolvers/concerns/caching_array_resolver.rb index 62649518142..15bf9a90e46 100644 --- a/app/graphql/resolvers/concerns/caching_array_resolver.rb +++ b/app/graphql/resolvers/concerns/caching_array_resolver.rb @@ -22,7 +22,7 @@ # # **important**: If the cardinality of your collection is likely to be greater than 100, # then you will want to pass `max_page_size:` as part of the field definition -# or (ideally) as part of the resolver `field_options`. +# or (ideally) set `max_page_size` in the resolver. # # How to implement: # -------------------- diff --git a/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb index 92fb9ec5cef..71833fbd2b9 100644 --- a/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb +++ b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb @@ -14,7 +14,8 @@ module WorkItems { work_item_type: :work_item_type, web_url: { namespace: :route, project: [:project_namespace, { namespace: :route }] }, - widgets: { work_item_type: :enabled_widget_definitions } + widgets: { work_item_type: :enabled_widget_definitions }, + archived: :project } end @@ -48,7 +49,8 @@ module WorkItems { project: [:project_feature, :group] }, - :author + :author, + *super ] end end diff --git a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb index 793b73342ab..187cb15ccc5 100644 --- a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb +++ b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb @@ -4,7 +4,6 @@ module Resolvers module ErrorTracking class SentryErrorsResolver < BaseResolver type Types::ErrorTracking::SentryErrorType.connection_type, null: true - extension Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension argument :search_term, ::GraphQL::Types::String, description: 'Search query for the Sentry error details.', @@ -31,10 +30,6 @@ module Resolvers Gitlab::Graphql::ExternallyPaginatedArray.new(previous_cursor, next_cursor, *issues) end - - def self.field_options - super.merge(connection: false) # we manage the pagination manually, so opt out of the connection field extension - end end end end diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb index 7bbc662c6c8..5e0fb27bafa 100644 --- a/app/graphql/resolvers/group_issues_resolver.rb +++ b/app/graphql/resolvers/group_issues_resolver.rb @@ -11,7 +11,11 @@ module Resolvers before_connection_authorization do |nodes, _| projects = nodes.map(&:project) - ActiveRecord::Associations::Preloader.new(records: projects, associations: :namespace).call + ActiveRecord::Associations::Preloader.new(records: projects, associations: project_associations).call + end + + def self.project_associations + [:namespace] end def ready?(**args) @@ -24,3 +28,5 @@ module Resolvers end end # rubocop:enable Graphql/ResolverType + +Resolvers::GroupIssuesResolver.prepend_mod diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb index 589366ba26d..34f14eee0e5 100644 --- a/app/graphql/resolvers/issues_resolver.rb +++ b/app/graphql/resolvers/issues_resolver.rb @@ -23,7 +23,11 @@ module Resolvers projects = nodes.map(&:project) ::Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects, current_user).execute ::Preloaders::GroupPolicyPreloader.new(projects.filter_map(&:group), current_user).execute - ActiveRecord::Associations::Preloader.new(records: projects, associations: :namespace).call + ActiveRecord::Associations::Preloader.new(records: projects, associations: project_associations).call + end + + def self.project_associations + [:namespace] end def ready?(**args) @@ -62,3 +66,5 @@ module Resolvers end end end + +Resolvers::IssuesResolver.prepend_mod diff --git a/app/graphql/resolvers/kas/agent_configurations_resolver.rb b/app/graphql/resolvers/kas/agent_configurations_resolver.rb index 74c5cbe55f1..6e35f64c2ee 100644 --- a/app/graphql/resolvers/kas/agent_configurations_resolver.rb +++ b/app/graphql/resolvers/kas/agent_configurations_resolver.rb @@ -3,7 +3,7 @@ module Resolvers module Kas class AgentConfigurationsResolver < BaseResolver - type Types::Kas::AgentConfigurationType, null: true + type Types::Kas::AgentConfigurationType.connection_type, null: true # Calls Gitaly via KAS calls_gitaly! diff --git a/app/graphql/resolvers/last_commit_resolver.rb b/app/graphql/resolvers/last_commit_resolver.rb index acf7826ab13..ff5701ede8c 100644 --- a/app/graphql/resolvers/last_commit_resolver.rb +++ b/app/graphql/resolvers/last_commit_resolver.rb @@ -12,7 +12,7 @@ module Resolvers # Ensure merge commits can be returned by sending nil to Gitaly instead of '/' path = tree.path == '/' ? nil : tree.path commit = Gitlab::Git::Commit.last_for_path(tree.repository, - ExtractsRef.qualify_ref(tree.sha, tree.ref_type), path, literal_pathspec: true) + ExtractsRef::RefExtractor.qualify_ref(tree.sha, tree.ref_type), path, literal_pathspec: true) ::Commit.new(commit, tree.repository.project) if commit end diff --git a/app/graphql/resolvers/merge_request_pipelines_resolver.rb b/app/graphql/resolvers/merge_request_pipelines_resolver.rb index deb698c63e1..45159e0edd5 100644 --- a/app/graphql/resolvers/merge_request_pipelines_resolver.rb +++ b/app/graphql/resolvers/merge_request_pipelines_resolver.rb @@ -11,9 +11,7 @@ module Resolvers # Return at most 500 pipelines for each MR. # Merge requests generally have many fewer pipelines than this. - def self.field_options - super.merge(max_page_size: 500) - end + max_page_size 500 def resolve(**args) return unless project diff --git a/app/graphql/resolvers/noteable/notes_resolver.rb b/app/graphql/resolvers/noteable/notes_resolver.rb index 0d25c747ffb..b4bd1068723 100644 --- a/app/graphql/resolvers/noteable/notes_resolver.rb +++ b/app/graphql/resolvers/noteable/notes_resolver.rb @@ -7,6 +7,11 @@ module Resolvers type Types::Notes::NoteType.connection_type, null: false + argument :filter, Types::WorkItems::NotesFilterTypeEnum, + required: false, + default_value: ::UserPreference::NOTES_FILTERS[:all_notes], + description: 'Type of notes collection: ALL_NOTES, ONLY_COMMENTS, ONLY_ACTIVITY.' + before_connection_authorization do |nodes, current_user| next if nodes.blank? @@ -16,8 +21,9 @@ module Resolvers ::Preloaders::Projects::NotesPreloader.new(project, current_user).call(nodes) end - def resolve_with_lookahead(*) - apply_lookahead(object.notes.fresh) + def resolve_with_lookahead(**args) + notes = NotesFinder.new(current_user, build_params(args)).execute + apply_lookahead(notes) end private @@ -31,6 +37,17 @@ module Resolvers award_emoji: [:award_emoji] } end + + def build_params(args) + params = { + project: object.project, + target: object + } + + params[:notes_filter] = args[:filter] if args[:filter].present? + + params + end end end end diff --git a/app/graphql/resolvers/package_pipelines_resolver.rb b/app/graphql/resolvers/package_pipelines_resolver.rb index 7f610915489..40e5456164a 100644 --- a/app/graphql/resolvers/package_pipelines_resolver.rb +++ b/app/graphql/resolvers/package_pipelines_resolver.rb @@ -5,7 +5,7 @@ module Resolvers include Gitlab::Graphql::Authorize::AuthorizeResource type Types::Ci::PipelineType.connection_type, null: true - extension Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension + extras [:lookahead] authorizes_object! authorize :read_pipeline @@ -41,14 +41,6 @@ module Resolvers end end - # we manage the pagination manually, so opt out of the connection field extension - def self.field_options - super.merge( - connection: false, - extras: [:lookahead] - ) - end - private def lazy_load_pipeline(id) @@ -59,6 +51,7 @@ module Resolvers def default_value_for(first:, last:, after:, before:) Gitlab::Graphql::Pagination::ActiveRecordArrayConnection.new( [], + context: context, first: first, last: last, after: after, diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb index de48fbafb04..48c94c144dd 100644 --- a/app/graphql/resolvers/paginated_tree_resolver.rb +++ b/app/graphql/resolvers/paginated_tree_resolver.rb @@ -3,7 +3,6 @@ module Resolvers class PaginatedTreeResolver < BaseResolver type Types::Tree::TreeType.connection_type, null: true - extension Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension calls_gitaly! @@ -50,9 +49,5 @@ module Resolvers extensions: { code: e.code, gitaly_code: e.status, service: e.service } ) end - - def self.field_options - super.merge(connection: false) # we manage the pagination manually, so opt out of the connection field extension - end end end diff --git a/app/graphql/resolvers/project_packages_protection_rules_resolver.rb b/app/graphql/resolvers/project_packages_protection_rules_resolver.rb new file mode 100644 index 00000000000..5d3d0fbf79d --- /dev/null +++ b/app/graphql/resolvers/project_packages_protection_rules_resolver.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Resolvers + class ProjectPackagesProtectionRulesResolver < BaseResolver + type Types::Packages::Protection::RuleType.connection_type, null: true + + alias_method :project, :object + + def resolve(**_args) + return [] if Feature.disabled?(:packages_protected_packages, project) + + project.package_protection_rules + end + end +end diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb index 08981f2c441..8dd409a8173 100644 --- a/app/graphql/resolvers/projects_resolver.rb +++ b/app/graphql/resolvers/projects_resolver.rb @@ -4,7 +4,7 @@ module Resolvers class ProjectsResolver < BaseResolver include ProjectSearchArguments - type Types::ProjectType, null: true + type Types::ProjectType.connection_type, null: true argument :ids, [GraphQL::Types::ID], required: false, diff --git a/app/graphql/resolvers/user_notes_count_resolver.rb b/app/graphql/resolvers/user_notes_count_resolver.rb index b91815c72f5..ebc54a1c6e8 100644 --- a/app/graphql/resolvers/user_notes_count_resolver.rb +++ b/app/graphql/resolvers/user_notes_count_resolver.rb @@ -20,7 +20,7 @@ module Resolvers def authorized_resource?(object) ability = "read_#{object.class.name.underscore}".to_sym - context[:current_user].present? && Ability.allowed?(context[:current_user], ability, object) + Ability.allowed?(context[:current_user], ability, object) end end end diff --git a/app/graphql/resolvers/work_items/ancestors_resolver.rb b/app/graphql/resolvers/work_items/ancestors_resolver.rb new file mode 100644 index 00000000000..33adbfc9c86 --- /dev/null +++ b/app/graphql/resolvers/work_items/ancestors_resolver.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Resolvers + module WorkItems + class AncestorsResolver < BaseResolver + prepend ::WorkItems::LookAheadPreloads + + type Types::WorkItemType.connection_type, null: true + + def resolve_with_lookahead + ancestors = object.ancestors + return WorkItem.none unless ancestors + + truncate_ancestors(apply_lookahead(ancestors)).reverse! + end + + private + + def truncate_ancestors(ancestors) + # Iterate from closest ancestor until root or first missing ancestor + authorized = authorized_ancestors(ancestors) + + previous_ancestor = object.work_item + authorized.take_while do |ancestor| + is_direct_parent = previous_ancestor.work_item_parent.id == ancestor.id + previous_ancestor = ancestor + + is_direct_parent + end + end + + def authorized_ancestors(ancestors) + preload_resource_parents(ancestors) + + DeclarativePolicy.user_scope do + ancestors.select { |ancestor| Ability.allowed?(current_user, :read_work_item, ancestor) } + end + end + + def preload_resource_parents(work_items) + projects = work_items.filter_map(&:project) + namespaces = work_items.filter_map(&:namespace) + group_namespaces = namespaces.select { |n| n.type == ::Group.sti_name } + + ::Preloaders::GroupPolicyPreloader.new(group_namespaces, current_user).execute if group_namespaces.any? + return unless projects.any? + + ::Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects, current_user).execute + ::Preloaders::GroupPolicyPreloader.new(projects.filter_map(&:namespace), current_user).execute + ActiveRecord::Associations::Preloader.new(records: projects, associations: [:namespace]).call + end + + def unconditional_includes + [:namespace, :work_item_parent, :work_item_type] + end + 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 index 35a6974163a..108d5d41b62 100644 --- a/app/graphql/resolvers/work_items/linked_items_resolver.rb +++ b/app/graphql/resolvers/work_items/linked_items_resolver.rb @@ -28,7 +28,7 @@ module Resolvers private def related_work_items(type) - return [] unless work_item.project.linked_work_items_feature_flag_enabled? + return [] unless work_item.resource_parent.linked_work_items_feature_flag_enabled? work_item.linked_work_items(current_user, preload: { project: [:project_feature, :group] }, link_type: type) end diff --git a/app/graphql/resolvers/work_items/work_item_discussions_resolver.rb b/app/graphql/resolvers/work_items/work_item_discussions_resolver.rb index b40d85e8003..0bbd51a537e 100644 --- a/app/graphql/resolvers/work_items/work_item_discussions_resolver.rb +++ b/app/graphql/resolvers/work_items/work_item_discussions_resolver.rb @@ -4,7 +4,6 @@ module Resolvers module WorkItems class WorkItemDiscussionsResolver < BaseResolver include Gitlab::Graphql::Authorize::AuthorizeResource - extension Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension authorize :read_work_item authorizes_object! @@ -31,11 +30,6 @@ module Resolvers ) end - def self.field_options - # we manage the pagination manually through external array, so opt out of the connection field extension - super.merge(connection: false) - end - def self.calculate_ext_conn_complexity true end diff --git a/app/graphql/types/achievements/user_achievement_type.rb b/app/graphql/types/achievements/user_achievement_type.rb index 7cdcb66576c..b92b2c42bee 100644 --- a/app/graphql/types/achievements/user_achievement_type.rb +++ b/app/graphql/types/achievements/user_achievement_type.rb @@ -48,6 +48,11 @@ module Types Types::TimeType, null: true, description: 'Timestamp the achievement was revoked.' + + field :priority, + GraphQL::Types::Int, + null: true, + description: 'Priority of the user achievement.' end end end diff --git a/app/graphql/types/base_argument.rb b/app/graphql/types/base_argument.rb index d2bc1d55408..cda7fa4a5df 100644 --- a/app/graphql/types/base_argument.rb +++ b/app/graphql/types/base_argument.rb @@ -7,7 +7,6 @@ module Types attr_reader :doc_reference def initialize(*args, **kwargs, &block) - init_gitlab_deprecation(kwargs) @doc_reference = kwargs.delete(:see) # our custom addition `nullable` which allows us to declare diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index 45e78b330fb..ca86e399f6b 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -5,12 +5,6 @@ module Types class BaseEnum < GraphQL::Schema::Enum class CustomValue < GraphQL::Schema::EnumValue include Gitlab::Graphql::Deprecations - - def initialize(name, desc = nil, **kwargs) - init_gitlab_deprecation(kwargs) - - super(name, desc, **kwargs) - end end enum_value_class(CustomValue) diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index caeb81c95cb..886490ba62f 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -11,13 +11,15 @@ module Types attr_reader :doc_reference def initialize(**kwargs, &block) - init_gitlab_deprecation(kwargs) - @calls_gitaly = !!kwargs.delete(:calls_gitaly) + @requires_argument = kwargs.delete(:requires_argument) + @calls_gitaly = kwargs.delete(:calls_gitaly) @doc_reference = kwargs.delete(:see) - @constant_complexity = kwargs[:complexity].is_a?(Integer) && kwargs[:complexity] > 0 - @requires_argument = !!kwargs.delete(:requires_argument) + + given_complexity = kwargs[:complexity] || kwargs[:resolver_class].try(:complexity) + @constant_complexity = given_complexity.is_a?(Integer) && given_complexity > 0 + kwargs[:complexity] = field_complexity(kwargs[:resolver_class], given_complexity) + @authorize = Array.wrap(kwargs.delete(:authorize)) - kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity]) after_connection_extensions = kwargs.delete(:late_extensions) || [] super(**kwargs, &block) @@ -31,11 +33,12 @@ module Types end def may_call_gitaly? - @constant_complexity || @calls_gitaly + @constant_complexity || calls_gitaly? end def requires_argument? - @requires_argument || arguments.values.any? { |argument| argument.type.non_null? } + value = @requires_argument.nil? ? @resolver_class.try(:requires_argument?) : @requires_argument + !!value || arguments.values.any? { |argument| argument.type.non_null? } end # By default fields authorize against the current object, but that is not how our @@ -82,7 +85,7 @@ module Types end def calls_gitaly? - @calls_gitaly + !!(@calls_gitaly.nil? ? @resolver_class.try(:calls_gitaly?) : @calls_gitaly) end def constant_complexity? diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb index 8a49c5a6a95..f01c63d717b 100644 --- a/app/graphql/types/ci/ci_cd_setting_type.rb +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -29,12 +29,6 @@ module Types null: true, description: 'Whether merge pipelines are enabled.', method: :merge_pipelines_enabled? - # TODO(Issue 422295): this is EE only and should be moved to the EE file - 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, diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index e18770c2708..6882a495259 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -16,20 +16,34 @@ module Types field :favicon, GraphQL::Types::String, null: true, description: 'Favicon of the status.' field :group, GraphQL::Types::String, null: true, - description: 'Group of the status.' + description: 'Group of the status.', + deprecated: { + reason: 'The `group` attribute is deprecated. Use `name` instead', + milestone: '16.4' + } field :has_details, GraphQL::Types::Boolean, null: true, description: 'Indicates if the status has further details.', method: :has_details? field :icon, GraphQL::Types::String, null: true, - description: 'Icon of the status.' + description: 'Icon of the status.', + deprecated: { + reason: 'The `icon` attribute is deprecated. Use `name` to ' \ + 'identify the status to display instead', + milestone: '16.4' + } field :id, GraphQL::Types::String, null: false, description: 'ID for a detailed status.', extras: [:parent] field :label, GraphQL::Types::String, null: true, - calls_gitaly: true, - description: 'Label of the status.' + description: 'Human-readable label of the status (e.g. success).' + field :name, GraphQL::Types::String, null: true, + description: 'Machine-readable status name (e.g. SUCCESS).' field :text, GraphQL::Types::String, null: true, - description: 'Text of the status.' + description: 'Text of the status.', + deprecated: { + reason: 'The `text` attribute is being deprecated. Use `label` instead', + milestone: '16.4' + } field :tooltip, GraphQL::Types::String, null: true, description: 'Tooltip associated with the status.', method: :status_tooltip diff --git a/app/graphql/types/ci/job_trace_type.rb b/app/graphql/types/ci/job_trace_type.rb index 405c640115d..62fb9340b53 100644 --- a/app/graphql/types/ci/job_trace_type.rb +++ b/app/graphql/types/ci/job_trace_type.rb @@ -21,7 +21,7 @@ module Types def html_summary(last_lines:) object.html( last_lines: last_lines.clamp(1, 100), - max_size: Feature.enabled?(:graphql_job_trace_html_summary_max_size) ? MAX_SIZE_B : nil + max_size: MAX_SIZE_B ).html_safe end end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index ba638d4bc47..dfdc3752916 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -18,6 +18,9 @@ module Types field :iid, GraphQL::Types::String, null: false, description: 'Internal ID of the pipeline.' + field :name, GraphQL::Types::String, null: true, + description: 'Name of the pipeline.' + field :sha, GraphQL::Types::String, null: true, method: :sha, description: "SHA of the pipeline's commit." do @@ -61,7 +64,7 @@ module Types description: "Timestamp of the pipeline's last activity." field :started_at, Types::TimeType, null: true, - description: 'Timestamp when the pipeline was started.' + description: 'Timestamp when the pipeline was started.' field :finished_at, Types::TimeType, null: true, description: "Timestamp of the pipeline's completion." @@ -178,6 +181,24 @@ module Types field :merge_request_event_type, Types::Ci::PipelineMergeRequestEventTypeEnum, null: true, description: "Event type of the pipeline associated with a merge request." + field :total_jobs, GraphQL::Types::Int, null: false, method: :total_size, description: "The total number of jobs in the pipeline" + + field :failure_reason, GraphQL::Types::String, null: true, description: "The reason why the pipeline failed" + + field :triggered_by_path, GraphQL::Types::String, null: true, description: "The path that triggered this pipeline" + + field :source, GraphQL::Types::String, null: true, method: :source, description: "The source of the pipeline" + + field :child, GraphQL::Types::Boolean, null: false, method: :child?, description: "If the pipeline is a child or not" + + field :latest, GraphQL::Types::Boolean, null: false, method: :latest?, calls_gitaly: true, description: "If the pipeline is the latest one or not" + + field :ref_text, GraphQL::Types::String, null: false, method: :ref_text, description: "The reference text from the presenter", calls_gitaly: true + + field :merge_request, Types::MergeRequestType, null: true, description: "The MR which the Pipeline is attached to" + + field :stuck, GraphQL::Types::Boolean, method: :stuck?, null: false, description: "If the pipeline is stuck." + def commit BatchLoader::GraphQL.wrap(object.commit) end diff --git a/app/graphql/types/clusters/agent_type.rb b/app/graphql/types/clusters/agent_type.rb index c0989796141..04a4a719ba1 100644 --- a/app/graphql/types/clusters/agent_type.rb +++ b/app/graphql/types/clusters/agent_type.rb @@ -33,7 +33,7 @@ module Types null: true, authorize: :read_project - field :tokens, Types::Clusters::AgentTokenType.connection_type, + field :tokens, description: 'Tokens associated with the cluster agent.', null: true, resolver: ::Resolvers::Clusters::AgentTokensResolver diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb index b02cd56e6df..08ac3172f2c 100644 --- a/app/graphql/types/custom_emoji_type.rb +++ b/app/graphql/types/custom_emoji_type.rb @@ -7,7 +7,7 @@ module Types authorize :read_custom_emoji - connection_type_class(Types::CountableConnectionType) + connection_type_class Types::CountableConnectionType expose_permissions Types::PermissionTypes::CustomEmoji diff --git a/app/graphql/types/error_tracking/sentry_error_collection_type.rb b/app/graphql/types/error_tracking/sentry_error_collection_type.rb index 9790560929b..009da29d9c7 100644 --- a/app/graphql/types/error_tracking/sentry_error_collection_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_collection_type.rb @@ -16,7 +16,8 @@ module Types resolver: Resolvers::ErrorTracking::SentryErrorStackTraceResolver field :errors, description: "Collection of Sentry Errors.", - resolver: Resolvers::ErrorTracking::SentryErrorsResolver + resolver: Resolvers::ErrorTracking::SentryErrorsResolver, + connection_extension: Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension field :external_url, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/issues/negated_issue_filter_input_type.rb b/app/graphql/types/issues/negated_issue_filter_input_type.rb index fc39efd2493..12f87509ade 100644 --- a/app/graphql/types/issues/negated_issue_filter_input_type.rb +++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb @@ -11,7 +11,7 @@ module Types argument :assignee_usernames, [GraphQL::Types::String], required: false, description: 'Usernames of users not assigned to the issue.' - argument :author_username, GraphQL::Types::String, + argument :author_username, [GraphQL::Types::String], required: false, description: "Username of a user who didn't author the issue." argument :iids, [GraphQL::Types::String], diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 4fd2b245de9..e6625e44508 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -102,6 +102,12 @@ module Types calls_gitaly: true, description: 'Detailed merge status of the merge request.' + field :mergeability_checks, [::Types::MergeRequests::MergeabilityCheckType], + null: false, + description: 'Status of all mergeability checks of the merge request.', + method: :all_mergeability_checks_results, + alpha: { milestone: '16.5' } + field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true, calls_gitaly: true, description: 'Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged.' diff --git a/app/graphql/types/merge_requests/mergeability_check_identifier_enum.rb b/app/graphql/types/merge_requests/mergeability_check_identifier_enum.rb new file mode 100644 index 00000000000..ac25c98941c --- /dev/null +++ b/app/graphql/types/merge_requests/mergeability_check_identifier_enum.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class MergeabilityCheckIdentifierEnum < BaseEnum + graphql_name 'MergeabilityCheckIdentifier' + description 'Representation of mergeability check identifier.' + + MergeRequest.all_mergeability_checks.each do |check_class| + identifier = check_class.identifier.to_s + + value identifier.upcase, + value: identifier, + description: "Mergeability check identifier is #{identifier}." + end + end + end +end diff --git a/app/graphql/types/merge_requests/mergeability_check_status_enum.rb b/app/graphql/types/merge_requests/mergeability_check_status_enum.rb new file mode 100644 index 00000000000..d3b95316b67 --- /dev/null +++ b/app/graphql/types/merge_requests/mergeability_check_status_enum.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class MergeabilityCheckStatusEnum < BaseEnum + graphql_name 'MergeabilityCheckStatus' + description 'Representation of whether a mergeability check passed, failed or is inactive.' + + value 'SUCCESS', + value: 'success', + description: 'Mergeability check has passed.' + + value 'FAILED', + value: 'failed', + description: 'Mergeability check has failed. The merge request cannot be merged.' + + value 'INACTIVE', + value: 'inactive', + description: 'Mergeability check is disabled via settings.' + end + end +end diff --git a/app/graphql/types/merge_requests/mergeability_check_type.rb b/app/graphql/types/merge_requests/mergeability_check_type.rb new file mode 100644 index 00000000000..4ef44c4b511 --- /dev/null +++ b/app/graphql/types/merge_requests/mergeability_check_type.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class MergeabilityCheckType < BaseObject # rubocop:disable Graphql/AuthorizeTypes + graphql_name 'MergeRequestMergeabilityCheck' + description 'Mergeability check of the merge request.' + + field :identifier, + ::Types::MergeRequests::MergeabilityCheckIdentifierEnum, + null: false, + description: 'Identifier of the mergeability check.' + + field :status, + ::Types::MergeRequests::MergeabilityCheckStatusEnum, + null: false, + description: 'Status of the mergeability check.' + + def status + object.status.to_s + end + + def identifier + object.identifier.to_s + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 445f26e2fcf..3af7140aed3 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -12,6 +12,7 @@ module Types mount_mutation Mutations::Achievements::DeleteUserAchievement, alpha: { milestone: '16.1' } mount_mutation Mutations::Achievements::Revoke, alpha: { milestone: '15.10' } mount_mutation Mutations::Achievements::Update, alpha: { milestone: '15.11' } + mount_mutation Mutations::Achievements::UpdateUserAchievementPriorities, alpha: { milestone: '16.5' } mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs mount_mutation Mutations::AlertManagement::CreateAlertIssue mount_mutation Mutations::AlertManagement::UpdateAlertStatus @@ -169,6 +170,7 @@ module Types mount_mutation Mutations::Packages::BulkDestroy, extensions: [::Gitlab::Graphql::Limit::FieldCallCount => { limit: 1 }] mount_mutation Mutations::Packages::DestroyFile + mount_mutation Mutations::Packages::Protection::Rule::Create, alpha: { milestone: '16.5' } mount_mutation Mutations::Packages::DestroyFiles mount_mutation Mutations::Packages::Cleanup::Policy::Update mount_mutation Mutations::Echo diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 3420f16213f..85bda507ff7 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -4,7 +4,7 @@ module Types class NamespaceType < BaseObject graphql_name 'Namespace' - authorize :read_namespace + authorize :read_namespace_via_membership field :id, GraphQL::Types::ID, null: false, description: 'ID of the namespace.' diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index e7e032c67c6..ffdaab0a5f6 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -5,6 +5,8 @@ module Types class NoteType < BaseObject graphql_name 'Note' + connection_type_class Types::CountableConnectionType + authorize :read_note expose_permissions Types::PermissionTypes::Note diff --git a/app/graphql/types/packages/helm/dependency_type.rb b/app/graphql/types/packages/helm/dependency_type.rb index 72a47d0af51..6ba14145fb5 100644 --- a/app/graphql/types/packages/helm/dependency_type.rb +++ b/app/graphql/types/packages/helm/dependency_type.rb @@ -12,7 +12,7 @@ module Types field :alias, GraphQL::Types::String, null: true, description: 'Alias of the dependency.', resolver_method: :resolve_alias field :condition, GraphQL::Types::String, null: true, description: 'Condition of the dependency.' field :enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates the dependency is enabled.' - field :import_values, [GraphQL::Types::JSON], null: true, description: 'Import-values of the dependency.', hash_key: "import-values" # rubocop:disable Graphql/JSONType + field :import_values, [GraphQL::Types::JSON], null: true, description: 'Import-values of the dependency.', hash_key: :'import-values' # rubocop:disable Graphql/JSONType field :name, GraphQL::Types::String, null: true, description: 'Name of the dependency.' field :repository, GraphQL::Types::String, null: true, description: 'Repository of the dependency.' field :tags, [GraphQL::Types::String], null: true, description: 'Tags of the dependency.' diff --git a/app/graphql/types/packages/helm/metadata_type.rb b/app/graphql/types/packages/helm/metadata_type.rb index ccc5a3029cd..77062a48bc3 100644 --- a/app/graphql/types/packages/helm/metadata_type.rb +++ b/app/graphql/types/packages/helm/metadata_type.rb @@ -10,8 +10,8 @@ module Types # Need to be synced with app/validators/json_schemas/helm_metadata.json field :annotations, GraphQL::Types::JSON, null: true, description: 'Annotations for the chart.' # rubocop:disable Graphql/JSONType - field :api_version, GraphQL::Types::String, null: false, description: 'API version of the chart.', hash_key: "apiVersion" - field :app_version, GraphQL::Types::String, null: true, description: 'App version of the chart.', hash_key: "appVersion" + field :api_version, GraphQL::Types::String, null: false, description: 'API version of the chart.', hash_key: :apiVersion + field :app_version, GraphQL::Types::String, null: true, description: 'App version of the chart.', hash_key: :appVersion field :condition, GraphQL::Types::String, null: true, description: 'Condition for the chart.' field :dependencies, [Types::Packages::Helm::DependencyType], null: true, description: 'Dependencies of the chart.' field :deprecated, GraphQL::Types::Boolean, null: true, description: 'Indicates if the chart is deprecated.' @@ -19,12 +19,12 @@ module Types field :home, GraphQL::Types::String, null: true, description: 'URL of the home page.' field :icon, GraphQL::Types::String, null: true, description: 'URL to an SVG or PNG image for the chart.' field :keywords, [GraphQL::Types::String], null: true, description: 'Keywords for the chart.' - field :kube_version, GraphQL::Types::String, null: true, description: 'Kubernetes versions for the chart.', hash_key: "kubeVersion" + field :kube_version, GraphQL::Types::String, null: true, description: 'Kubernetes versions for the chart.', hash_key: :kubeVersion field :maintainers, [Types::Packages::Helm::MaintainerType], null: true, description: 'Maintainers of the chart.' field :name, GraphQL::Types::String, null: false, description: 'Name of the chart.' field :sources, [GraphQL::Types::String], null: true, description: 'URLs of the source code for the chart.' field :tags, GraphQL::Types::String, null: true, description: 'Tags for the chart.' - field :type, GraphQL::Types::String, null: true, description: 'Type of the chart.', hash_key: "appVersion" + field :type, GraphQL::Types::String, null: true, description: 'Type of the chart.', hash_key: :appVersion field :version, GraphQL::Types::String, null: false, description: 'Version of the chart.' end end diff --git a/app/graphql/types/packages/package_base_type.rb b/app/graphql/types/packages/package_base_type.rb index cc41169bcda..aa580d48709 100644 --- a/app/graphql/types/packages/package_base_type.rb +++ b/app/graphql/types/packages/package_base_type.rb @@ -23,6 +23,7 @@ module Types field :package_type, Types::Packages::PackageTypeEnum, null: false, description: 'Package type.' field :project, Types::ProjectType, null: false, description: 'Project where the package is stored.' field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.' + field :status_message, GraphQL::Types::String, null: true, description: 'Status message.' field :tags, Types::Packages::PackageTagType.connection_type, null: true, description: 'Package tags.' field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' field :version, GraphQL::Types::String, null: true, description: 'Version string.' diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index f6586670c72..4c5b16cc41e 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -10,6 +10,7 @@ module Types field :pipelines, resolver: Resolvers::PackagePipelinesResolver, + connection_extension: Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension, description: <<-DESC Pipelines that built the package. Max page size #{Resolvers::PackagePipelinesResolver::MAX_PAGE_SIZE}. DESC diff --git a/app/graphql/types/packages/protection/rule_access_level_enum.rb b/app/graphql/types/packages/protection/rule_access_level_enum.rb new file mode 100644 index 00000000000..098a3e48100 --- /dev/null +++ b/app/graphql/types/packages/protection/rule_access_level_enum.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + module Packages + module Protection + class RuleAccessLevelEnum < BaseEnum + graphql_name 'PackagesProtectionRuleAccessLevel' + description 'Access level of a package protection rule resource' + + ::Packages::Protection::Rule.push_protected_up_to_access_levels.each_key do |access_level_key| + value access_level_key.upcase, value: access_level_key.to_s, + description: "#{access_level_key.capitalize} access." + end + end + end + end +end diff --git a/app/graphql/types/packages/protection/rule_package_type_enum.rb b/app/graphql/types/packages/protection/rule_package_type_enum.rb new file mode 100644 index 00000000000..28e9df76adc --- /dev/null +++ b/app/graphql/types/packages/protection/rule_package_type_enum.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + module Packages + module Protection + class RulePackageTypeEnum < BaseEnum + graphql_name 'PackagesProtectionRulePackageType' + description 'Package type of a package protection rule resource' + + ::Packages::Protection::Rule.package_types.each_key do |package_type| + value package_type.upcase, value: package_type, + description: "Packages of the #{package_type} format" + end + end + end + end +end diff --git a/app/graphql/types/packages/protection/rule_type.rb b/app/graphql/types/packages/protection/rule_type.rb new file mode 100644 index 00000000000..1e969d39ce2 --- /dev/null +++ b/app/graphql/types/packages/protection/rule_type.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Types + module Packages + module Protection + class RuleType < ::Types::BaseObject + graphql_name 'PackagesProtectionRule' + description 'A packages protection rule designed to protect packages ' \ + 'from being pushed by users with a certain access level.' + + authorize :admin_package + + field :package_name_pattern, + GraphQL::Types::String, + null: false, + description: + 'Package name protected by the protection rule. For example `@my-scope/my-package-*`. ' \ + 'Wildcard character `*` allowed.' + + field :package_type, + Types::Packages::Protection::RulePackageTypeEnum, + null: false, + description: 'Package type protected by the protection rule. For example `NPM`.' + + field :push_protected_up_to_access_level, + Types::Packages::Protection::RuleAccessLevelEnum, + null: false, + description: + 'Max GitLab access level unable to push a package. For example `DEVELOPER`, `MAINTAINER`, `OWNER`.' + end + end + end +end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 2738d4da6c2..95caefc3825 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -311,6 +311,12 @@ module Types null: true, description: 'Packages cleanup policy for the project.' + field :packages_protection_rules, + Types::Packages::Protection::RuleType.connection_type, + null: true, + description: 'Packages protection rules for the project.', + resolver: Resolvers::ProjectPackagesProtectionRulesResolver + field :jobs, type: Types::Ci::JobType.connection_type, null: true, @@ -524,7 +530,7 @@ module Types complexity: 5, resolver: ::Resolvers::TimelogResolver - field :agent_configurations, ::Types::Kas::AgentConfigurationType.connection_type, + field :agent_configurations, null: true, description: 'Agent configurations defined by the project', resolver: ::Resolvers::Kas::AgentConfigurationsResolver diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index d02b3e4136f..d185007f05b 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -109,7 +109,7 @@ module Types null: true, resolver: Resolvers::ProjectResolver, description: "Find a project." - field :projects, Types::ProjectType.connection_type, + field :projects, null: true, resolver: Resolvers::ProjectsResolver, description: "Find projects visible to the current user." @@ -154,7 +154,7 @@ module Types null: true, resolver: Resolvers::TopicsResolver, description: "Find project topics." - field :usage_trends_measurements, Types::Admin::Analytics::UsageTrends::MeasurementType.connection_type, + field :usage_trends_measurements, null: true, description: 'Get statistics on the instance.', resolver: Resolvers::Admin::Analytics::UsageTrends::MeasurementsResolver diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb index 40eade3a4d1..a012b60b1c6 100644 --- a/app/graphql/types/repository_type.rb +++ b/app/graphql/types/repository_type.rb @@ -20,6 +20,7 @@ module Types field :exists, GraphQL::Types::Boolean, null: false, method: :exists?, calls_gitaly: true, description: 'Indicates a corresponding Git repository exists on disk.' field :paginated_tree, Types::Tree::TreeType.connection_type, null: true, resolver: Resolvers::PaginatedTreeResolver, calls_gitaly: true, + connection_extension: Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension, max_page_size: 100, description: 'Paginated tree of the repository.' field :root_ref, GraphQL::Types::String, null: true, calls_gitaly: true, diff --git a/app/graphql/types/security/codequality_reports_comparer_type.rb b/app/graphql/types/security/codequality_reports_comparer_type.rb index 3b0f790af81..8088bf84627 100644 --- a/app/graphql/types/security/codequality_reports_comparer_type.rb +++ b/app/graphql/types/security/codequality_reports_comparer_type.rb @@ -11,7 +11,7 @@ module Types field :report, type: CodequalityReportsComparer::ReportType, null: true, - hash_key: 'data', + hash_key: :data, description: 'Compared codequality report.' end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 6e6d0edbe15..16f01979a43 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -45,6 +45,11 @@ module Types description: 'Visibility Level of the snippet.', null: false + field :hidden, GraphQL::Types::Boolean, + description: 'Indicates the snippet is hidden because the author has been banned.', + null: false, + method: :hidden_due_to_author_ban? + field :created_at, Types::TimeType, description: 'Timestamp this snippet was created.', null: false diff --git a/app/graphql/types/todo_action_enum.rb b/app/graphql/types/todo_action_enum.rb index 45b83ea1d64..63f96332eab 100644 --- a/app/graphql/types/todo_action_enum.rb +++ b/app/graphql/types/todo_action_enum.rb @@ -13,5 +13,6 @@ module Types 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.' + value 'okr_checkin_requested', value: 12, description: 'An OKR assigned to the user requires an update.' end end diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index 9e5f6810aca..47d486265b0 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -160,7 +160,7 @@ module Types description: "Achievements for the user. " \ "Only returns for namespaces where the `achievements` feature flag is enabled.", extras: [:lookahead], - resolver: ::Resolvers::Achievements::UserAchievementsResolver + resolver: ::Resolvers::Achievements::UserAchievementsForUserResolver field :bio, type: ::GraphQL::Types::String, diff --git a/app/graphql/types/user_state_enum.rb b/app/graphql/types/user_state_enum.rb index de15fc19682..72503840bf5 100644 --- a/app/graphql/types/user_state_enum.rb +++ b/app/graphql/types/user_state_enum.rb @@ -5,8 +5,11 @@ module Types graphql_name 'UserState' description 'Possible states of a user' - value 'active', 'User is active and is able to use the system.', value: 'active' - value 'blocked', 'User has been blocked and is prevented from using the system.', value: 'blocked' - value 'deactivated', 'User is no longer active and is unable to use the system.', value: 'deactivated' + value 'active', 'User is active and can use the system.', value: 'active' + value 'blocked', 'User has been blocked by an administrator and cannot use the system.', value: 'blocked' + value 'deactivated', 'User is no longer active and cannot use the system.', value: 'deactivated' + value 'banned', 'User is blocked, and their contributions are hidden.', value: 'banned' + value 'ldap_blocked', 'User has been blocked by the system.', value: 'ldap_blocked' + value 'blocked_pending_approval', 'User is blocked and pending approval.', value: 'blocked_pending_approval' end end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 170f28103eb..87ca5fddf14 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -4,6 +4,9 @@ module Types class UserType < ::Types::BaseObject graphql_name 'UserCore' description 'Core representation of a GitLab user.' + + connection_type_class Types::CountableConnectionType + implements ::Types::UserInterface authorize :read_user diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb index 05798ba3d2f..103a1c0ec9b 100644 --- a/app/graphql/types/work_item_type.rb +++ b/app/graphql/types/work_item_type.rb @@ -58,6 +58,10 @@ module Types field :work_item_type, Types::WorkItems::TypeType, null: false, description: 'Type assigned to the work item.' + field :archived, GraphQL::Types::Boolean, null: false, + description: 'Whether the work item belongs to an archived project. Always false for group level work items.', + alpha: { milestone: '16.5' } + markdown_field :title_html, null: true markdown_field :description_html, null: true @@ -70,5 +74,11 @@ module Types def create_note_email object.creatable_note_email_address(context[:current_user]) end + + def archived + return false if object.project.blank? + + object.project.archived? + end end end diff --git a/app/graphql/types/work_items/widgets/hierarchy_type.rb b/app/graphql/types/work_items/widgets/hierarchy_type.rb index 4ec8ec84779..41c5af2ce63 100644 --- a/app/graphql/types/work_items/widgets/hierarchy_type.rb +++ b/app/graphql/types/work_items/widgets/hierarchy_type.rb @@ -20,6 +20,12 @@ module Types null: true, complexity: 5, description: 'Child work items.' + field :ancestors, ::Types::WorkItemType.connection_type, + null: true, complexity: 5, + description: 'Ancestors (parents) of the work item.', + extras: [:lookahead], + resolver: Resolvers::WorkItems::AncestorsResolver + field :has_children, GraphQL::Types::Boolean, null: false, description: 'Indicates if the work item has children.' diff --git a/app/graphql/types/work_items/widgets/notes_type.rb b/app/graphql/types/work_items/widgets/notes_type.rb index 7da2777beee..199001649bb 100644 --- a/app/graphql/types/work_items/widgets/notes_type.rb +++ b/app/graphql/types/work_items/widgets/notes_type.rb @@ -18,7 +18,8 @@ module Types field :discussions, Types::Notes::DiscussionType.connection_type, null: true, description: "Notes on this work item.", - resolver: Resolvers::WorkItems::WorkItemDiscussionsResolver + resolver: Resolvers::WorkItems::WorkItemDiscussionsResolver, + connection_extension: Gitlab::Graphql::Extensions::ForwardOnlyExternallyPaginatedArrayExtension end # rubocop:enable Graphql/AuthorizeTypes end |