Skip to content

Draft: Update graphql types to include project import level

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

Loading