Skip to content

Draft: Update graphql types to include project import level

Carla Drago requested to merge 358750-graphql-changes into master

What does this MR do and why?

Describe in detail what your merge request does and why.

This change updates GraphQL types to include the project_import_level namespace setting. It is the first of several changes required to make project_import_level configurable through the UI or api. See: #358750 (closed)

Testing

Enter the following query in http://gdk.test:3000/-/graphql-explorer:

{
  group(fullPath: "gitlab-org") {
    projectImportLevel
  }
}

Result:

{
  "data": {
    "group": {
      "projectImportLevel": "owner"
    }
  }
}

Query Plan

UPDATE: This association has been removed in favour of something that uses an existing method. So a Query Plan is likely no longer necessary.

There is a new association on the User model to find all groups a user can import projects to:

has_many :import_groups, -> { joins(:namespace_settings) .where("namespace_settings.project_import_level<>0 AND members.access_level>=namespace_settings.project_import_level") }, through: :group_members, source: :group

This creates a query that looks like (using a sample User):

SELECT "namespaces"."id", "namespaces"."name", "namespaces"."path", "namespaces"."owner_id", "namespaces"."created_at", "namespaces"."updated_at", "namespaces"."type", "namespaces"."description", "namespaces"."avatar", "namespaces"."membership_lock", "namespaces"."share_with_group_lock", "namespaces"."visibility_level", "namespaces"."request_access_enabled", "namespaces"."ldap_sync_status", "namespaces"."ldap_sync_error", "namespaces"."ldap_sync_last_update_at", "namespaces"."ldap_sync_last_successful_update_at", "namespaces"."ldap_sync_last_sync_at", "namespaces"."description_html", "namespaces"."lfs_enabled", "namespaces"."parent_id", "namespaces"."shared_runners_minutes_limit", "namespaces"."repository_size_limit", "namespaces"."require_two_factor_authentication", "namespaces"."two_factor_grace_period", "namespaces"."cached_markdown_version", "namespaces"."project_creation_level", "namespaces"."runners_token", "namespaces"."file_template_project_id", "namespaces"."saml_discovery_token", "namespaces"."runners_token_encrypted", "namespaces"."custom_project_templates_group_id", "namespaces"."auto_devops_enabled", "namespaces"."extra_shared_runners_minutes_limit", "namespaces"."last_ci_minutes_notification_at", "namespaces"."last_ci_minutes_usage_notification_level", "namespaces"."subgroup_creation_level", "namespaces"."emails_disabled", "namespaces"."max_pages_size", "namespaces"."max_artifacts_size", "namespaces"."mentions_disabled", "namespaces"."default_branch_protection", "namespaces"."unlock_membership_to_ldap", "namespaces"."max_personal_access_token_lifetime", "namespaces"."push_rule_id", "namespaces"."shared_runners_enabled", "namespaces"."allow_descendants_override_disabled_shared_runners", "namespaces"."traversal_ids" FROM "namespaces" INNER JOIN "members" ON "namespaces"."id" = "members"."source_id" INNER JOIN "namespace_settings" ON "namespace_settings"."namespace_id" = "namespaces"."id" WHERE "members"."type" = 'GroupMember' AND "members"."source_type" = 'Namespace' AND "namespaces"."type" = 'Group' AND "members"."user_id" = 1 AND "members"."requested_at" IS NULL AND (access_level >= 10) AND (namespace_settings.project_import_level<>0) AND (members.access_level>=namespace_settings.project_import_level)

With a plan: https://gitlab.slack.com/files/UL8QB0T4J/F042EGKCXMW/plan-text.txt

Nested Loop (cost=1.56..13.39 rows=1 width=365) (actual time=0.096..1.302 rows=23 loops=1) Buffers: shared hit=594 I/O Timings: read=0.000 write=0.000 -> Nested Loop (cost=1.13..12.82 rows=1 width=373) (actual time=0.076..0.756 rows=59 loops=1) Buffers: shared hit=358 I/O Timings: read=0.000 write=0.000 -> Index Scan using index_members_on_user_id_source_id_source_type on public.members (cost=0.56..9.24 rows=1 width=8) (actual time=0.057..0.218 rows=59 loops=1) Index Cond: ((members.user_id = 1) AND ((members.source_type)::text = 'Namespace'::text)) Filter: ((members.requested_at IS NULL) AND (members.access_level >= 10) AND ((members.type)::text = 'GroupMember'::text)) Rows Removed by Filter: 0 Buffers: shared hit=63 I/O Timings: read=0.000 write=0.000 -> Index Scan using namespaces_pkey on public.namespaces (cost=0.56..3.58 rows=1 width=365) (actual time=0.008..0.008 rows=1 loops=59) Index Cond: (namespaces.id = members.source_id) Filter: ((namespaces.type)::text = 'Group'::text) Rows Removed by Filter: 0 Buffers: shared hit=295 I/O Timings: read=0.000 write=0.000 -> Index Scan using namespace_settings_pkey on public.namespace_settings (cost=0.43..0.55 rows=1 width=6) (actual time=0.008..0.009 rows=1 loops=59) Index Cond: (namespace_settings.namespace_id = namespaces.id) Filter: (namespace_settings.project_import_level <> 0) Rows Removed by Filter: 0 Buffers: shared hit=236 I/O Timings: read=0.000 write=0.000

Recommendations: Looks good

Summary:

Time: 2.948 ms

  • planning: 1.515 ms
  • execution: 1.433 ms
    • I/O read: 0.000 ms
    • I/O write: 0.000 ms

Shared buffers:

  • ~~hits: 594 (~4.60 MiB) from the buffer pool~~
  • reads: 0 from the OS file cache, including disk I/O
  • dirtied: 0
  • writes: 0

Details and Visulizations: https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/12014/commands/42620

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #358750 (closed)

Edited by Carla Drago

Merge request reports