Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9bf40d9fdc
commit
11f742d4e7
|
|
@ -374,7 +374,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/administration/integration/kroki.md @msedlakjakubowski
|
||||
/doc/administration/integration/mailgun.md @msedlakjakubowski
|
||||
/doc/administration/integration/plantuml.md @aqualls
|
||||
/doc/administration/integration/terminal.md @ashrafkhamis
|
||||
/doc/administration/integration/terminal.md @phillipwells
|
||||
/doc/administration/invalidate_markdown_cache.md @msedlakjakubowski
|
||||
/doc/administration/issue_closing_pattern.md @aqualls
|
||||
/doc/administration/job_artifacts.md @marcel.amirault
|
||||
|
|
@ -386,27 +386,45 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/administration/logs/log_parsing.md @axil
|
||||
/doc/administration/logs/tracing_correlation_id.md @axil
|
||||
/doc/administration/maintenance_mode/ @axil
|
||||
/doc/administration/merge_request_diffs.md @aqualls
|
||||
/doc/administration/monitoring/ @msedlakjakubowski
|
||||
/doc/administration/merge_request_diffs.md @ashrafkhamis
|
||||
/doc/administration/monitoring/github_imports.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/gitlab_self_monitoring_project/ @msedlakjakubowski
|
||||
/doc/administration/monitoring/index.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/ip_allowlist.md @sselhorn
|
||||
/doc/administration/monitoring/performance/ @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/ @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/gitlab_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/gitlab_metrics.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/index.md @axil
|
||||
/doc/administration/monitoring/prometheus/node_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/pgbouncer_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/postgres_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/redis_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/registry_exporter.md @msedlakjakubowski
|
||||
/doc/administration/monitoring/prometheus/web_exporter.md @sselhorn
|
||||
/doc/administration/nfs.md @axil
|
||||
/doc/administration/object_storage.md @axil
|
||||
/doc/administration/operations/ @axil
|
||||
/doc/administration/operations/fast_ssh_key_lookup.md @aqualls
|
||||
/doc/administration/operations/filesystem_benchmarking.md @axil
|
||||
/doc/administration/operations/index.md @axil
|
||||
/doc/administration/operations/moving_repositories.md @eread
|
||||
/doc/administration/operations/puma.md @axil
|
||||
/doc/administration/operations/rails_console.md @axil
|
||||
/doc/administration/operations/ssh_certificates.md @axil
|
||||
/doc/administration/package_information/ @axil
|
||||
/doc/administration/packages/ @claytoncornell
|
||||
/doc/administration/pages/ @aqualls
|
||||
/doc/administration/pages/ @ashrafkhamis
|
||||
/doc/administration/polling.md @axil
|
||||
/doc/administration/postgresql/ @aqualls
|
||||
/doc/administration/raketasks/ @axil
|
||||
/doc/administration/raketasks/check.md @axil
|
||||
/doc/administration/raketasks/geo.md @axil
|
||||
/doc/administration/raketasks/github_import.md @axil
|
||||
/doc/administration/raketasks/ldap.md @eread
|
||||
/doc/administration/raketasks/maintenance.md @axil
|
||||
/doc/administration/raketasks/praefect.md @eread
|
||||
/doc/administration/raketasks/project_import_export.md @axil
|
||||
/doc/administration/raketasks/smtp.md @axil
|
||||
/doc/administration/raketasks/storage.md @axil
|
||||
/doc/administration/raketasks/uploads/ @axil
|
||||
/doc/administration/read_only_gitlab.md @axil
|
||||
/doc/administration/redis/ @axil
|
||||
/doc/administration/reference_architectures/ @axil
|
||||
|
|
@ -417,18 +435,28 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/administration/repository_storage_types.md @eread
|
||||
/doc/administration/restart_gitlab.md @axil
|
||||
/doc/administration/server_hooks.md @eread
|
||||
/doc/administration/sidekiq/ @axil
|
||||
/doc/administration/sidekiq/extra_sidekiq_processes.md @axil
|
||||
/doc/administration/sidekiq/extra_sidekiq_routing.md @axil
|
||||
/doc/administration/sidekiq/index.md @axil
|
||||
/doc/administration/sidekiq/sidekiq_health_check.md @axil
|
||||
/doc/administration/sidekiq/sidekiq_memory_killer.md @sselhorn
|
||||
/doc/administration/sidekiq/sidekiq_troubleshooting.md @axil
|
||||
/doc/administration/smime_signing_email.md @axil
|
||||
/doc/administration/snippets/ @aqualls
|
||||
/doc/administration/static_objects_external_storage.md @aqualls
|
||||
/doc/administration/snippets/ @ashrafkhamis
|
||||
/doc/administration/static_objects_external_storage.md @ashrafkhamis
|
||||
/doc/administration/system_hooks.md @ashrafkhamis
|
||||
/doc/administration/terraform_state.md @phillipwells
|
||||
/doc/administration/timezone.md @axil
|
||||
/doc/administration/troubleshooting/ @axil
|
||||
/doc/administration/troubleshooting/diagnostics_tools.md @axil
|
||||
/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md @axil
|
||||
/doc/administration/troubleshooting/index.md @axil
|
||||
/doc/administration/troubleshooting/linux_cheat_sheet.md @axil
|
||||
/doc/administration/troubleshooting/postgresql.md @aqualls
|
||||
/doc/administration/troubleshooting/ssl.md @axil
|
||||
/doc/administration/troubleshooting/test_environments.md @axil
|
||||
/doc/administration/uploads.md @axil
|
||||
/doc/administration/user_settings.md @eread
|
||||
/doc/administration/wikis/ @aqualls
|
||||
/doc/administration/wikis/ @ashrafkhamis
|
||||
/doc/api/access_requests.md @eread
|
||||
/doc/api/admin_sidekiq_queues.md @axil
|
||||
/doc/api/alert_management_alerts.md @msedlakjakubowski
|
||||
|
|
@ -445,7 +473,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/cluster_agents.md @phillipwells
|
||||
/doc/api/commits.md @aqualls
|
||||
/doc/api/container_registry.md @claytoncornell
|
||||
/doc/api/custom_attributes.md @ashrafkhamis
|
||||
/doc/api/custom_attributes.md @msedlakjakubowski
|
||||
/doc/api/dependencies.md @rdickenson
|
||||
/doc/api/dependency_proxy.md @claytoncornell
|
||||
/doc/api/deploy_keys.md @rdickenson
|
||||
|
|
@ -466,9 +494,14 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/features.md @rdickenson
|
||||
/doc/api/freeze_periods.md @rdickenson
|
||||
/doc/api/geo_nodes.md @axil
|
||||
/doc/api/graphql/ @ashrafkhamis
|
||||
/doc/api/graphql/audit_report.md @eread
|
||||
/doc/api/graphql/custom_emoji.md @msedlakjakubowski
|
||||
/doc/api/graphql/getting_started.md @ashrafkhamis
|
||||
/doc/api/graphql/index.md @ashrafkhamis
|
||||
/doc/api/graphql/reference/ @ashrafkhamis
|
||||
/doc/api/graphql/removed_items.md @ashrafkhamis
|
||||
/doc/api/graphql/sample_issue_boards.md @msedlakjakubowski
|
||||
/doc/api/graphql/users_example.md @eread
|
||||
/doc/api/group_access_tokens.md @eread
|
||||
/doc/api/group_activity_analytics.md @fneill
|
||||
/doc/api/group_badges.md @fneill
|
||||
|
|
@ -482,8 +515,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/group_protected_environments.md @rdickenson
|
||||
/doc/api/group_relations_export.md @eread
|
||||
/doc/api/group_releases.md @rdickenson
|
||||
/doc/api/group_repository_storage_moves.md @aqualls
|
||||
/doc/api/group_wikis.md @aqualls
|
||||
/doc/api/group_repository_storage_moves.md @ashrafkhamis
|
||||
/doc/api/group_wikis.md @ashrafkhamis
|
||||
/doc/api/groups.md @fneill
|
||||
/doc/api/import.md @eread
|
||||
/doc/api/index.md @ashrafkhamis
|
||||
|
|
@ -509,7 +542,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/merge_request_context_commits.md @aqualls
|
||||
/doc/api/merge_requests.md @aqualls
|
||||
/doc/api/merge_trains.md @marcel.amirault
|
||||
/doc/api/metadata.md @ashrafkhamis
|
||||
/doc/api/metadata.md @phillipwells
|
||||
/doc/api/metrics_dashboard_annotations.md @msedlakjakubowski
|
||||
/doc/api/metrics_user_starred_dashboards.md @msedlakjakubowski
|
||||
/doc/api/milestones.md @msedlakjakubowski
|
||||
|
|
@ -520,8 +553,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/openapi/ @ashrafkhamis
|
||||
/doc/api/packages.md @claytoncornell
|
||||
/doc/api/packages/ @claytoncornell
|
||||
/doc/api/pages.md @aqualls
|
||||
/doc/api/pages_domains.md @aqualls
|
||||
/doc/api/pages.md @ashrafkhamis
|
||||
/doc/api/pages_domains.md @ashrafkhamis
|
||||
/doc/api/personal_access_tokens.md @eread
|
||||
/doc/api/pipeline_schedules.md @marcel.amirault
|
||||
/doc/api/pipeline_triggers.md @marcel.amirault
|
||||
|
|
@ -535,7 +568,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/project_level_variables.md @marcel.amirault
|
||||
/doc/api/project_relations_export.md @eread
|
||||
/doc/api/project_repository_storage_moves.md @eread
|
||||
/doc/api/project_snippets.md @aqualls
|
||||
/doc/api/project_snippets.md @ashrafkhamis
|
||||
/doc/api/project_statistics.md @aqualls
|
||||
/doc/api/project_templates.md @aqualls
|
||||
/doc/api/project_vulnerabilities.md @aqualls
|
||||
|
|
@ -556,12 +589,12 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/resource_weight_events.md @msedlakjakubowski
|
||||
/doc/api/runners.md @sselhorn
|
||||
/doc/api/scim.md @eread
|
||||
/doc/api/search.md @aqualls
|
||||
/doc/api/search.md @ashrafkhamis
|
||||
/doc/api/secure_files.md @marcel.amirault
|
||||
/doc/api/settings.md @eread
|
||||
/doc/api/sidekiq_metrics.md @axil
|
||||
/doc/api/snippet_repository_storage_moves.md @aqualls
|
||||
/doc/api/snippets.md @aqualls
|
||||
/doc/api/snippet_repository_storage_moves.md @ashrafkhamis
|
||||
/doc/api/snippets.md @ashrafkhamis
|
||||
/doc/api/statistics.md @eread
|
||||
/doc/api/status_checks.md @eread
|
||||
/doc/api/suggestions.md @aqualls
|
||||
|
|
@ -575,16 +608,18 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/api/topics.md @fneill
|
||||
/doc/api/usage_data.md @claytoncornell
|
||||
/doc/api/users.md @eread
|
||||
/doc/api/version.md @ashrafkhamis
|
||||
/doc/api/version.md @phillipwells
|
||||
/doc/api/visual_review_discussions.md @marcel.amirault
|
||||
/doc/api/vulnerabilities.md @claytoncornell
|
||||
/doc/api/vulnerability_exports.md @claytoncornell
|
||||
/doc/api/vulnerability_findings.md @claytoncornell
|
||||
/doc/api/wikis.md @aqualls
|
||||
/doc/api/wikis.md @ashrafkhamis
|
||||
/doc/architecture/blueprints/ci_pipeline_components/ @marcel.amirault
|
||||
/doc/architecture/blueprints/container_registry_metadata_database/ @claytoncornell
|
||||
/doc/architecture/blueprints/database/scalability/patterns/ @aqualls
|
||||
/doc/architecture/blueprints/database_scaling/ @aqualls
|
||||
/doc/architecture/blueprints/gitlab_to_kubernetes_communication/ @phillipwells
|
||||
/doc/architecture/blueprints/work_items/ @msedlakjakubowski
|
||||
/doc/ci/ @marcel.amirault
|
||||
/doc/ci/caching/ @marcel.amirault
|
||||
/doc/ci/chatops/ @phillipwells
|
||||
|
|
@ -626,8 +661,16 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/ci/services/ @sselhorn
|
||||
/doc/ci/ssh_keys/ @marcel.amirault
|
||||
/doc/ci/test_cases/ @msedlakjakubowski
|
||||
/doc/ci/testing/ @marcel.amirault
|
||||
/doc/ci/testing/accessibility_testing.md @marcel.amirault
|
||||
/doc/ci/testing/browser_performance_testing.md @marcel.amirault
|
||||
/doc/ci/testing/code_quality.md @rdickenson
|
||||
/doc/ci/testing/fail_fast_testing.md @marcel.amirault
|
||||
/doc/ci/testing/index.md @marcel.amirault
|
||||
/doc/ci/testing/load_performance_testing.md @marcel.amirault
|
||||
/doc/ci/testing/metrics_reports.md @marcel.amirault
|
||||
/doc/ci/testing/test_coverage_visualization.md @marcel.amirault
|
||||
/doc/ci/testing/unit_test_report_examples.md @marcel.amirault
|
||||
/doc/ci/testing/unit_test_reports.md @marcel.amirault
|
||||
/doc/ci/triggers/ @marcel.amirault
|
||||
/doc/ci/variables/ @marcel.amirault
|
||||
/doc/ci/yaml/ @marcel.amirault
|
||||
|
|
@ -645,9 +688,57 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/cicd/ @marcel.amirault
|
||||
/doc/development/code_intelligence/ @aqualls
|
||||
/doc/development/contributing/ @sselhorn
|
||||
/doc/development/database/ @aqualls
|
||||
/doc/development/database/add_foreign_key_to_existing_column.md @aqualls
|
||||
/doc/development/database/adding_database_indexes.md @aqualls
|
||||
/doc/development/database/avoiding_downtime_in_migrations.md @aqualls
|
||||
/doc/development/database/background_migrations.md @aqualls
|
||||
/doc/development/database/batched_background_migrations.md @aqualls
|
||||
/doc/development/database/ci_mirrored_tables.md @aqualls
|
||||
/doc/development/database/client_side_connection_pool.md @aqualls
|
||||
/doc/development/database/constraint_naming_convention.md @aqualls
|
||||
/doc/development/database/creating_enums.md @aqualls
|
||||
/doc/development/database/database_debugging.md @aqualls
|
||||
/doc/development/database/database_dictionary.md @aqualls
|
||||
/doc/development/database/database_lab.md @aqualls
|
||||
/doc/development/database/database_migration_pipeline.md @aqualls
|
||||
/doc/development/database/database_query_comments.md @aqualls
|
||||
/doc/development/database/database_reviewer_guidelines.md @aqualls
|
||||
/doc/development/database/db_dump.md @aqualls
|
||||
/doc/development/database/dbcheck-migrations-job.md @aqualls
|
||||
/doc/development/database/deleting_migrations.md @aqualls
|
||||
/doc/development/database/efficient_in_operator_queries.md @aqualls
|
||||
/doc/development/database/filtering_by_label.md @msedlakjakubowski
|
||||
/doc/development/database/foreign_keys.md @aqualls
|
||||
/doc/development/database/hash_indexes.md @aqualls
|
||||
/doc/development/database/index.md @aqualls
|
||||
/doc/development/database/insert_into_tables_in_batches.md @aqualls
|
||||
/doc/development/database/iterating_tables_in_batches.md @aqualls
|
||||
/doc/development/database/keyset_pagination.md @aqualls
|
||||
/doc/development/database/layout_and_access_patterns.md @aqualls
|
||||
/doc/development/database/loose_foreign_keys.md @aqualls
|
||||
/doc/development/database/maintenance_operations.md @aqualls
|
||||
/doc/development/database/migrations_for_multiple_databases.md @aqualls
|
||||
/doc/development/database/multiple_databases.md @sselhorn
|
||||
/doc/development/database/not_null_constraints.md @aqualls
|
||||
/doc/development/database/ordering_table_columns.md @aqualls
|
||||
/doc/development/database/pagination_guidelines.md @aqualls
|
||||
/doc/development/database/pagination_performance_guidelines.md @aqualls
|
||||
/doc/development/database/polymorphic_associations.md @aqualls
|
||||
/doc/development/database/post_deployment_migrations.md @aqualls
|
||||
/doc/development/database/query_count_limits.md @aqualls
|
||||
/doc/development/database/query_performance.md @aqualls
|
||||
/doc/development/database/query_recorder.md @aqualls
|
||||
/doc/development/database/rename_database_tables.md @aqualls
|
||||
/doc/development/database/serializing_data.md @aqualls
|
||||
/doc/development/database/setting_multiple_values.md @aqualls
|
||||
/doc/development/database/sha1_as_binary.md @aqualls
|
||||
/doc/development/database/single_table_inheritance.md @aqualls
|
||||
/doc/development/database/strings_and_the_text_data_type.md @aqualls
|
||||
/doc/development/database/swapping_tables.md @aqualls
|
||||
/doc/development/database/table_partitioning.md @aqualls
|
||||
/doc/development/database/transaction_guidelines.md @aqualls
|
||||
/doc/development/database/understanding_explain_plans.md @aqualls
|
||||
/doc/development/database/verifying_database_capabilities.md @aqualls
|
||||
/doc/development/database_review.md @aqualls
|
||||
/doc/development/developing_with_solargraph.md @aqualls
|
||||
/doc/development/development_processes.md @sselhorn
|
||||
|
|
@ -659,11 +750,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/elasticsearch.md @ashrafkhamis
|
||||
/doc/development/experiment_guide/ @phillipwells
|
||||
/doc/development/export_csv.md @eread
|
||||
/doc/development/fe_guide/content_editor.md @aqualls
|
||||
/doc/development/fe_guide/content_editor.md @ashrafkhamis
|
||||
/doc/development/fe_guide/dark_mode.md @sselhorn
|
||||
/doc/development/fe_guide/graphql.md @sselhorn
|
||||
/doc/development/fe_guide/merge_request_widget_extensions.md @aqualls
|
||||
/doc/development/fe_guide/source_editor.md @aqualls
|
||||
/doc/development/fe_guide/source_editor.md @ashrafkhamis
|
||||
/doc/development/fe_guide/view_component.md @rdickenson
|
||||
/doc/development/feature_categorization/ @sselhorn
|
||||
/doc/development/feature_development.md @sselhorn
|
||||
|
|
@ -673,8 +764,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/geo/ @axil
|
||||
/doc/development/git_object_deduplication.md @eread
|
||||
/doc/development/gitaly.md @eread
|
||||
/doc/development/gitlab_flavored_markdown/ @aqualls
|
||||
/doc/development/gitlab_flavored_markdown/specification_guide/ @aqualls
|
||||
/doc/development/gitlab_flavored_markdown/ @ashrafkhamis
|
||||
/doc/development/gitlab_flavored_markdown/specification_guide/ @ashrafkhamis
|
||||
/doc/development/graphql_guide/batchloader.md @aqualls
|
||||
/doc/development/graphql_guide/graphql_pro.md @ashrafkhamis
|
||||
/doc/development/graphql_guide/index.md @ashrafkhamis
|
||||
|
|
@ -684,8 +775,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/image_scaling.md @sselhorn
|
||||
/doc/development/import_export.md @eread
|
||||
/doc/development/index.md @sselhorn
|
||||
/doc/development/integrations/ @ashrafkhamis
|
||||
/doc/development/integrations/secure.md @claytoncornell
|
||||
/doc/development/integrations/codesandbox.md @sselhorn
|
||||
/doc/development/integrations/index.md @ashrafkhamis
|
||||
/doc/development/integrations/jenkins.md @ashrafkhamis
|
||||
/doc/development/integrations/jira_connect.md @ashrafkhamis
|
||||
/doc/development/integrations/secure.md @rdickenson
|
||||
/doc/development/integrations/secure_partner_integration.md @rdickenson
|
||||
/doc/development/internal_api/ @aqualls
|
||||
/doc/development/internal_users.md @sselhorn
|
||||
|
|
@ -698,7 +792,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/merge_request_concepts/ @aqualls
|
||||
/doc/development/omnibus.md @axil
|
||||
/doc/development/packages/ @claytoncornell
|
||||
/doc/development/pages/ @aqualls
|
||||
/doc/development/pages/ @ashrafkhamis
|
||||
/doc/development/permissions.md @eread
|
||||
/doc/development/policies.md @eread
|
||||
/doc/development/product_qualified_lead_guide/ @phillipwells
|
||||
|
|
@ -716,7 +810,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/development/testing_guide/end_to_end/ @sselhorn
|
||||
/doc/development/value_stream_analytics.md @fneill
|
||||
/doc/development/value_stream_analytics/ @fneill
|
||||
/doc/development/wikis.md @aqualls
|
||||
/doc/development/wikis.md @ashrafkhamis
|
||||
/doc/development/work_items.md @msedlakjakubowski
|
||||
/doc/development/work_items_widgets.md @msedlakjakubowski
|
||||
/doc/development/workhorse/ @aqualls
|
||||
|
|
@ -725,13 +819,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/drawers/ @ashrafkhamis
|
||||
/doc/gitlab-basics/ @aqualls
|
||||
/doc/install/ @axil
|
||||
/doc/install/aws/ @axil
|
||||
/doc/install/azure/ @axil
|
||||
/doc/install/cloud_native/ @axil
|
||||
/doc/install/google_cloud_platform/ @axil
|
||||
/doc/install/openshift_and_gitlab/ @axil
|
||||
/doc/integration/advanced_search/ @ashrafkhamis
|
||||
/doc/integration/akismet.md @ashrafkhamis
|
||||
/doc/integration/akismet.md @phillipwells
|
||||
/doc/integration/alicloud.md @eread
|
||||
/doc/integration/arkose.md @phillipwells
|
||||
/doc/integration/auth0.md @eread
|
||||
|
|
@ -744,7 +833,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/integration/facebook.md @eread
|
||||
/doc/integration/github.md @eread
|
||||
/doc/integration/gitlab.md @eread
|
||||
/doc/integration/gitpod.md @aqualls
|
||||
/doc/integration/gitpod.md @ashrafkhamis
|
||||
/doc/integration/gmail_action_buttons_for_gitlab.md @ashrafkhamis
|
||||
/doc/integration/google.md @eread
|
||||
/doc/integration/index.md @ashrafkhamis
|
||||
|
|
@ -756,7 +845,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/integration/oauth_provider.md @eread
|
||||
/doc/integration/omniauth.md @eread
|
||||
/doc/integration/openid_connect_provider.md @eread
|
||||
/doc/integration/recaptcha.md @ashrafkhamis
|
||||
/doc/integration/recaptcha.md @eread
|
||||
/doc/integration/salesforce.md @eread
|
||||
/doc/integration/saml.md @eread
|
||||
/doc/integration/security_partners/ @rdickenson
|
||||
|
|
@ -774,10 +863,18 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/operations/product_analytics.md @claytoncornell
|
||||
/doc/operations/tracing.md @msedlakjakubowski
|
||||
/doc/policy/ @axil
|
||||
/doc/raketasks/ @axil
|
||||
/doc/raketasks/backup_gitlab.md @axil
|
||||
/doc/raketasks/backup_restore.md @axil
|
||||
/doc/raketasks/cleanup.md @axil
|
||||
/doc/raketasks/generate_sample_prometheus_data.md @msedlakjakubowski
|
||||
/doc/raketasks/migrate_snippets.md @aqualls
|
||||
/doc/raketasks/import.md @axil
|
||||
/doc/raketasks/index.md @axil
|
||||
/doc/raketasks/list_repos.md @axil
|
||||
/doc/raketasks/migrate_snippets.md @ashrafkhamis
|
||||
/doc/raketasks/restore_gitlab.md @axil
|
||||
/doc/raketasks/spdx.md @rdickenson
|
||||
/doc/raketasks/user_management.md @axil
|
||||
/doc/raketasks/web_hooks.md @axil
|
||||
/doc/raketasks/x509_signatures.md @aqualls
|
||||
/doc/security/ @eread
|
||||
/doc/subscriptions/ @fneill
|
||||
|
|
@ -795,10 +892,17 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/topics/offline/ @axil
|
||||
/doc/topics/plan_and_track.md @msedlakjakubowski
|
||||
/doc/tutorials/ @kpaizee
|
||||
/doc/update/ @axil
|
||||
/doc/update/index.md @axil
|
||||
/doc/update/mysql_to_postgresql.md @aqualls
|
||||
/doc/update/package/ @axil
|
||||
/doc/update/patch_versions.md @axil
|
||||
/doc/update/plan_your_upgrade.md @axil
|
||||
/doc/update/restore_after_failure.md @axil
|
||||
/doc/update/upgrading_from_ce_to_ee.md @axil
|
||||
/doc/update/upgrading_from_source.md @axil
|
||||
/doc/update/upgrading_postgresql_using_slony.md @aqualls
|
||||
/doc/update/with_downtime.md @axil
|
||||
/doc/update/zero_downtime.md @axil
|
||||
/doc/user/admin_area/analytics/ @fneill
|
||||
/doc/user/admin_area/broadcast_messages.md @phillipwells
|
||||
/doc/user/admin_area/credentials_inventory.md @eread
|
||||
|
|
@ -838,10 +942,16 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/user/admin_area/settings/usage_statistics.md @claytoncornell
|
||||
/doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls
|
||||
/doc/user/analytics/ci_cd_analytics.md @rdickenson
|
||||
/doc/user/analytics/ @fneill
|
||||
/doc/user/analytics/code_review_analytics.md @fneill
|
||||
/doc/user/analytics/index.md @fneill
|
||||
/doc/user/analytics/issue_analytics.md @fneill
|
||||
/doc/user/analytics/merge_request_analytics.md @fneill
|
||||
/doc/user/analytics/productivity_analytics.md @fneill
|
||||
/doc/user/analytics/repository_analytics.md @fneill
|
||||
/doc/user/analytics/value_stream_analytics.md @fneill
|
||||
/doc/user/application_security/api_fuzzing/ @rdickenson
|
||||
/doc/user/application_security/configuration/ @rdickenson
|
||||
/doc/user/application_security/container_scanning/ @claytoncornell
|
||||
/doc/user/application_security/container_scanning/ @rdickenson
|
||||
/doc/user/application_security/coverage_fuzzing/ @rdickenson
|
||||
/doc/user/application_security/cve_id_request.md @claytoncornell
|
||||
/doc/user/application_security/dast/ @rdickenson
|
||||
|
|
@ -913,6 +1023,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/user/packages/dependency_proxy/ @claytoncornell
|
||||
/doc/user/packages/generic_packages/ @claytoncornell
|
||||
/doc/user/packages/go_proxy/ @claytoncornell
|
||||
/doc/user/packages/harbor_container_registry/ @claytoncornell
|
||||
/doc/user/packages/helm_repository/ @claytoncornell
|
||||
/doc/user/packages/infrastructure_registry/ @phillipwells
|
||||
/doc/user/packages/maven_repository/ @claytoncornell
|
||||
|
|
@ -929,6 +1040,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/user/profile/notifications.md @msedlakjakubowski
|
||||
/doc/user/profile/personal_access_tokens.md @eread
|
||||
/doc/user/profile/unknown_sign_in_notification.md @eread
|
||||
/doc/user/profile/wrong_two_factor_authentication_code_notification.md @eread
|
||||
/doc/user/project/autocomplete_characters.md @aqualls
|
||||
/doc/user/project/badges.md @aqualls
|
||||
/doc/user/project/clusters/ @phillipwells
|
||||
|
|
@ -942,48 +1054,133 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
|
|||
/doc/user/project/file_lock.md @aqualls
|
||||
/doc/user/project/git_attributes.md @aqualls
|
||||
/doc/user/project/highlighting.md @aqualls
|
||||
/doc/user/project/import/ @eread
|
||||
/doc/user/project/import/bitbucket.md @eread
|
||||
/doc/user/project/import/bitbucket_server.md @eread
|
||||
/doc/user/project/import/clearcase.md @eread
|
||||
/doc/user/project/import/cvs.md @eread
|
||||
/doc/user/project/import/fogbugz.md @eread
|
||||
/doc/user/project/import/gitea.md @eread
|
||||
/doc/user/project/import/github.md @eread
|
||||
/doc/user/project/import/gitlab_com.md @eread
|
||||
/doc/user/project/import/index.md @eread
|
||||
/doc/user/project/import/jira.md @msedlakjakubowski
|
||||
/doc/user/project/import/manifest.md @eread
|
||||
/doc/user/project/import/perforce.md @eread
|
||||
/doc/user/project/import/phabricator.md @eread
|
||||
/doc/user/project/import/repo_by_url.md @eread
|
||||
/doc/user/project/import/svn.md @eread
|
||||
/doc/user/project/import/tfvc.md @eread
|
||||
/doc/user/project/index.md @fneill
|
||||
/doc/user/project/integrations/ @ashrafkhamis
|
||||
/doc/user/project/insights/ @fneill
|
||||
/doc/user/project/integrations/asana.md @ashrafkhamis
|
||||
/doc/user/project/integrations/bamboo.md @ashrafkhamis
|
||||
/doc/user/project/integrations/bugzilla.md @ashrafkhamis
|
||||
/doc/user/project/integrations/custom_issue_tracker.md @ashrafkhamis
|
||||
/doc/user/project/integrations/discord_notifications.md @ashrafkhamis
|
||||
/doc/user/project/integrations/emails_on_push.md @ashrafkhamis
|
||||
/doc/user/project/integrations/ewm.md @ashrafkhamis
|
||||
/doc/user/project/integrations/github.md @ashrafkhamis
|
||||
/doc/user/project/integrations/gitlab_slack_application.md @ashrafkhamis
|
||||
/doc/user/project/integrations/hangouts_chat.md @ashrafkhamis
|
||||
/doc/user/project/integrations/harbor.md @ashrafkhamis
|
||||
/doc/user/project/integrations/index.md @ashrafkhamis
|
||||
/doc/user/project/integrations/irker.md @ashrafkhamis
|
||||
/doc/user/project/integrations/mattermost.md @ashrafkhamis
|
||||
/doc/user/project/integrations/mattermost_slash_commands.md @ashrafkhamis
|
||||
/doc/user/project/integrations/microsoft_teams.md @ashrafkhamis
|
||||
/doc/user/project/integrations/mock_ci.md @ashrafkhamis
|
||||
/doc/user/project/integrations/pipeline_status_emails.md @ashrafkhamis
|
||||
/doc/user/project/integrations/pivotal_tracker.md @ashrafkhamis
|
||||
/doc/user/project/integrations/prometheus.md @msedlakjakubowski
|
||||
/doc/user/project/integrations/prometheus_library/ @msedlakjakubowski
|
||||
/doc/user/project/integrations/pumble.md @ashrafkhamis
|
||||
/doc/user/project/integrations/redmine.md @ashrafkhamis
|
||||
/doc/user/project/integrations/servicenow.md @ashrafkhamis
|
||||
/doc/user/project/integrations/shimo.md @ashrafkhamis
|
||||
/doc/user/project/integrations/slack.md @ashrafkhamis
|
||||
/doc/user/project/integrations/slack_slash_commands.md @ashrafkhamis
|
||||
/doc/user/project/integrations/unify_circuit.md @ashrafkhamis
|
||||
/doc/user/project/integrations/webex_teams.md @ashrafkhamis
|
||||
/doc/user/project/integrations/webhook_events.md @ashrafkhamis
|
||||
/doc/user/project/integrations/webhooks.md @ashrafkhamis
|
||||
/doc/user/project/integrations/youtrack.md @ashrafkhamis
|
||||
/doc/user/project/integrations/zentao.md @ashrafkhamis
|
||||
/doc/user/project/issue_board.md @msedlakjakubowski
|
||||
/doc/user/project/issues/ @msedlakjakubowski
|
||||
/doc/user/project/issues/associate_zoom_meeting.md @msedlakjakubowski
|
||||
/doc/user/project/issues/confidential_issues.md @msedlakjakubowski
|
||||
/doc/user/project/issues/crosslinking_issues.md @msedlakjakubowski
|
||||
/doc/user/project/issues/csv_import.md @eread
|
||||
/doc/user/project/issues/design_management.md @msedlakjakubowski
|
||||
/doc/user/project/issues/due_dates.md @msedlakjakubowski
|
||||
/doc/user/project/issues/index.md @msedlakjakubowski
|
||||
/doc/user/project/issues/issue_weight.md @msedlakjakubowski
|
||||
/doc/user/project/issues/managing_issues.md @msedlakjakubowski
|
||||
/doc/user/project/issues/multiple_assignees_for_issues.md @msedlakjakubowski
|
||||
/doc/user/project/issues/related_issues.md @msedlakjakubowski
|
||||
/doc/user/project/issues/sorting_issue_lists.md @msedlakjakubowski
|
||||
/doc/user/project/labels.md @msedlakjakubowski
|
||||
/doc/user/project/members/ @fneill
|
||||
/doc/user/project/merge_requests/ @aqualls
|
||||
/doc/user/project/merge_requests/allow_collaboration.md @aqualls
|
||||
/doc/user/project/merge_requests/approvals/ @aqualls
|
||||
/doc/user/project/merge_requests/authorization_for_merge_requests.md @aqualls
|
||||
/doc/user/project/merge_requests/changes.md @aqualls
|
||||
/doc/user/project/merge_requests/cherry_pick_changes.md @aqualls
|
||||
/doc/user/project/merge_requests/commit_templates.md @aqualls
|
||||
/doc/user/project/merge_requests/commits.md @aqualls
|
||||
/doc/user/project/merge_requests/confidential.md @aqualls
|
||||
/doc/user/project/merge_requests/conflicts.md @aqualls
|
||||
/doc/user/project/merge_requests/creating_merge_requests.md @aqualls
|
||||
/doc/user/project/merge_requests/csv_export.md @eread
|
||||
/doc/user/project/merge_requests/dependencies.md @aqualls
|
||||
/doc/user/project/merge_requests/drafts.md @aqualls
|
||||
/doc/user/project/merge_requests/getting_started.md @aqualls
|
||||
/doc/user/project/merge_requests/index.md @aqualls
|
||||
/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md @aqualls
|
||||
/doc/user/project/merge_requests/methods/ @aqualls
|
||||
/doc/user/project/merge_requests/revert_changes.md @aqualls
|
||||
/doc/user/project/merge_requests/reviews/ @aqualls
|
||||
/doc/user/project/merge_requests/squash_and_merge.md @aqualls
|
||||
/doc/user/project/merge_requests/status_checks.md @eread
|
||||
/doc/user/project/merge_requests/versions.md @aqualls
|
||||
/doc/user/project/merge_requests/widgets.md @aqualls
|
||||
/doc/user/project/milestones/ @msedlakjakubowski
|
||||
/doc/user/project/pages/ @aqualls
|
||||
/doc/user/project/pages/custom_domains_ssl_tls_certification/ @aqualls
|
||||
/doc/user/project/pages/getting_started/ @aqualls
|
||||
/doc/user/project/pages/ @ashrafkhamis
|
||||
/doc/user/project/protected_branches.md @aqualls
|
||||
/doc/user/project/protected_tags.md @aqualls
|
||||
/doc/user/project/push_options.md @aqualls
|
||||
/doc/user/project/quick_actions.md @msedlakjakubowski
|
||||
/doc/user/project/releases/ @rdickenson
|
||||
/doc/user/project/repository/ @aqualls
|
||||
/doc/user/project/repository/branches/ @aqualls
|
||||
/doc/user/project/repository/csv.md @aqualls
|
||||
/doc/user/project/repository/file_finder.md @ashrafkhamis
|
||||
/doc/user/project/repository/forking_workflow.md @aqualls
|
||||
/doc/user/project/repository/git_blame.md @aqualls
|
||||
/doc/user/project/repository/git_history.md @aqualls
|
||||
/doc/user/project/repository/gpg_signed_commits/ @aqualls
|
||||
/doc/user/project/repository/index.md @aqualls
|
||||
/doc/user/project/repository/jupyter_notebooks/ @aqualls
|
||||
/doc/user/project/repository/managing_large_repositories.md @axil
|
||||
/doc/user/project/repository/mirror/ @aqualls
|
||||
/doc/user/project/repository/push_rules.md @aqualls
|
||||
/doc/user/project/repository/reducing_the_repo_size_using_git.md @eread
|
||||
/doc/user/project/repository/vscode.md @aqualls
|
||||
/doc/user/project/repository/web_editor.md @ashrafkhamis
|
||||
/doc/user/project/repository/x509_signed_commits/ @aqualls
|
||||
/doc/user/project/requirements/ @msedlakjakubowski
|
||||
/doc/user/project/service_desk.md @msedlakjakubowski
|
||||
/doc/user/project/settings/import_export.md @eread
|
||||
/doc/user/project/settings/index.md @fneill
|
||||
/doc/user/project/settings/project_access_tokens.md @eread
|
||||
/doc/user/project/time_tracking.md @msedlakjakubowski
|
||||
/doc/user/project/web_ide/ @aqualls
|
||||
/doc/user/project/wiki/ @aqualls
|
||||
/doc/user/project/web_ide/ @ashrafkhamis
|
||||
/doc/user/project/wiki/ @ashrafkhamis
|
||||
/doc/user/project/working_with_projects.md @fneill
|
||||
/doc/user/public_access.md @fneill
|
||||
/doc/user/reserved_names.md @fneill
|
||||
/doc/user/search/ @ashrafkhamis
|
||||
/doc/user/search/global_search/ @ashrafkhamis
|
||||
/doc/user/shortcuts.md @aqualls
|
||||
/doc/user/snippets.md @aqualls
|
||||
/doc/user/shortcuts.md @ashrafkhamis
|
||||
/doc/user/snippets.md @ashrafkhamis
|
||||
/doc/user/ssh.md @eread
|
||||
/doc/user/tasks.md @msedlakjakubowski
|
||||
/doc/user/todos.md @msedlakjakubowski
|
||||
|
|
|
|||
|
|
@ -19,26 +19,6 @@ Layout/FirstArrayElementIndentation:
|
|||
- 'spec/lib/gitlab/gitaly_client/blob_service_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/importer/notes_importer_spec.rb'
|
||||
- 'spec/lib/gitlab/github_import/parallel_scheduling_spec.rb'
|
||||
- 'spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb'
|
||||
- 'spec/lib/gitlab/hook_data/release_builder_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/group/tree_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/group/tree_saver_spec.rb'
|
||||
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
|
||||
- 'spec/lib/gitlab/kubernetes/rollout_instances_spec.rb'
|
||||
- 'spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb'
|
||||
- 'spec/lib/gitlab/pagination/keyset/column_order_definition_spec.rb'
|
||||
- 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/query_builder_spec.rb'
|
||||
- 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/order_values_loader_strategy_spec.rb'
|
||||
- 'spec/lib/gitlab/pagination/keyset/iterator_spec.rb'
|
||||
- 'spec/lib/gitlab/pagination/keyset/order_spec.rb'
|
||||
- 'spec/lib/gitlab/project_transfer_spec.rb'
|
||||
- 'spec/lib/gitlab/prometheus_client_spec.rb'
|
||||
- 'spec/lib/gitlab/push_options_spec.rb'
|
||||
- 'spec/lib/gitlab/rack_attack/request_spec.rb'
|
||||
- 'spec/lib/gitlab/search/abuse_detection_spec.rb'
|
||||
- 'spec/lib/gitlab/search/found_blob_spec.rb'
|
||||
- 'spec/lib/gitlab/serializer/ci/variables_spec.rb'
|
||||
- 'spec/lib/gitlab/sidekiq_config_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import api from '~/api';
|
||||
import { __ } from '~/locale';
|
||||
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
|
||||
import HelpPopover from '~/vue_shared/components/help_popover.vue';
|
||||
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
|
|
@ -115,9 +114,6 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
collapseText() {
|
||||
return this.isCollapsed ? __('Expand') : __('Collapse');
|
||||
},
|
||||
isLoading() {
|
||||
return this.status === status.LOADING;
|
||||
},
|
||||
|
|
@ -172,6 +168,11 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
toggleCollapsed() {
|
||||
// Because the top-level div is always clickable, we need to check if we can collapse.
|
||||
if (!this.isCollapsible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.trackAction) {
|
||||
api.trackRedisHllUserEvent(this.trackAction);
|
||||
}
|
||||
|
|
@ -186,9 +187,9 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<section class="media-section">
|
||||
<div class="media">
|
||||
<div class="media" :class="{ 'gl-cursor-pointer': isCollapsible }" @click="toggleCollapsed">
|
||||
<status-icon :status="statusIconName" :size="24" class="align-self-center" />
|
||||
<div class="media-body d-flex flex-align-self-center align-items-center">
|
||||
<div class="media-body gl-display-flex gl-align-items-flex-start gl-flex-direction-row!">
|
||||
<div data-testid="report-section-code-text" class="js-code-text code-text">
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<p class="gl-line-height-normal gl-m-0">{{ headerText }}</p>
|
||||
|
|
@ -204,14 +205,19 @@ export default {
|
|||
|
||||
<slot name="action-buttons" :is-collapsible="isCollapsible"></slot>
|
||||
|
||||
<gl-button
|
||||
<div
|
||||
v-if="isCollapsible"
|
||||
data-testid="report-section-expand-button"
|
||||
data-qa-selector="expand_report_button"
|
||||
@click="toggleCollapsed"
|
||||
class="gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3"
|
||||
>
|
||||
{{ collapseText }}
|
||||
</gl-button>
|
||||
<gl-button
|
||||
data-testid="report-section-expand-button"
|
||||
data-qa-selector="expand_report_button"
|
||||
category="tertiary"
|
||||
size="small"
|
||||
:icon="isExpanded ? 'chevron-lg-up' : 'chevron-lg-down'"
|
||||
@click.stop="toggleCollapsed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { joinPaths } from '~/lib/utils/url_utility';
|
||||
import { normalizeData } from 'ee_else_ce/repository/utils/commit';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { COMMIT_BATCH_SIZE, I18N_COMMIT_DATA_FETCH_ERROR } from './constants';
|
||||
|
||||
let requestedOffsets = [];
|
||||
|
|
@ -43,7 +43,7 @@ const fetchData = (projectPath, path, ref, offset) => {
|
|||
return axios
|
||||
.get(url, { params: { format: 'json', offset } })
|
||||
.then(({ data }) => normalizeData(data, path))
|
||||
.catch(() => createFlash({ message: I18N_COMMIT_DATA_FETCH_ERROR }));
|
||||
.catch(() => createAlert({ message: I18N_COMMIT_DATA_FETCH_ERROR }));
|
||||
};
|
||||
|
||||
export const loadCommits = async (projectPath, path, ref, offset) => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { uniqueId } from 'lodash';
|
|||
import BlobContent from '~/blob/components/blob_content.vue';
|
||||
import BlobHeader from '~/blob/components/blob_header.vue';
|
||||
import { SIMPLE_BLOB_VIEWER, RICH_BLOB_VIEWER } from '~/blob/components/constants';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { isLoggedIn, handleLocationHash } from '~/lib/utils/common_utils';
|
||||
import { __ } from '~/locale';
|
||||
|
|
@ -271,7 +271,7 @@ export default {
|
|||
.catch(() => this.displayError());
|
||||
},
|
||||
displayError() {
|
||||
createFlash({ message: __('An error occurred while loading the file. Please try again.') });
|
||||
createAlert({ message: __('An error occurred while loading the file. Please try again.') });
|
||||
},
|
||||
switchViewer(newViewer) {
|
||||
this.activeViewerType = newViewer || SIMPLE_BLOB_VIEWER;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import getRefMixin from '~/repository/mixins/get_ref';
|
||||
import initSourcegraph from '~/sourcegraph';
|
||||
import ShortcutsBlob from '~/behaviors/shortcuts/shortcuts_blob';
|
||||
|
|
@ -36,7 +36,7 @@ export default {
|
|||
return !this.filePath;
|
||||
},
|
||||
error() {
|
||||
createFlash({ message: this.$options.i18n.errorMessage });
|
||||
createAlert({ message: this.$options.i18n.errorMessage });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
GlFormTextarea,
|
||||
GlToggle,
|
||||
} from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
|
|
@ -140,7 +140,7 @@ export default {
|
|||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
createFlash({ message: ERROR_MESSAGE });
|
||||
createAlert({ message: ERROR_MESSAGE });
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import paginatedTreeQuery from 'shared_queries/repository/paginated_tree.query.graphql';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
||||
import { __ } from '~/locale';
|
||||
import {
|
||||
|
|
@ -142,7 +142,7 @@ export default {
|
|||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('An error occurred while fetching folder content.'),
|
||||
});
|
||||
throw error;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
GlButton,
|
||||
GlAlert,
|
||||
} from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { ContentTypeMultipartFormData } from '~/lib/utils/headers';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
|
|
@ -171,7 +171,7 @@ export default {
|
|||
})
|
||||
.catch(() => {
|
||||
this.loading = false;
|
||||
createFlash({ message: ERROR_MESSAGE });
|
||||
createAlert({ message: ERROR_MESSAGE });
|
||||
});
|
||||
},
|
||||
formData() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
|
||||
|
|
@ -13,7 +13,7 @@ export const fetchGroups = ({ commit }, search) => {
|
|||
commit(types.RECEIVE_GROUPS_SUCCESS, data);
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash({ message: __('There was a problem fetching groups.') });
|
||||
createAlert({ message: __('There was a problem fetching groups.') });
|
||||
commit(types.RECEIVE_GROUPS_ERROR);
|
||||
});
|
||||
};
|
||||
|
|
@ -23,7 +23,7 @@ export const fetchProjects = ({ commit, state }, search) => {
|
|||
const groupId = state.query?.group_id;
|
||||
|
||||
const handleCatch = () => {
|
||||
createFlash({ message: __('There was an error fetching projects') });
|
||||
createAlert({ message: __('There was an error fetching projects') });
|
||||
commit(types.RECEIVE_PROJECTS_ERROR);
|
||||
};
|
||||
const handleSuccess = ({ data }) => {
|
||||
|
|
@ -59,7 +59,7 @@ export const loadFrequentGroups = async ({ commit, state }) => {
|
|||
const inflatedData = mergeById(await Promise.all(promises), storedData);
|
||||
commit(types.LOAD_FREQUENT_ITEMS, { key: GROUPS_LOCAL_STORAGE_KEY, data: inflatedData });
|
||||
} catch {
|
||||
createFlash({ message: __('There was a problem fetching recent groups.') });
|
||||
createAlert({ message: __('There was a problem fetching recent groups.') });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ export const loadFrequentProjects = async ({ commit, state }) => {
|
|||
const inflatedData = mergeById(await Promise.all(promises), storedData);
|
||||
commit(types.LOAD_FREQUENT_ITEMS, { key: PROJECTS_LOCAL_STORAGE_KEY, data: inflatedData });
|
||||
} catch {
|
||||
createFlash({ message: __('There was a problem fetching recent projects.') });
|
||||
createAlert({ message: __('There was a problem fetching recent projects.') });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import createFlash, { hideFlash } from './flash';
|
||||
import { createAlert, hideFlash } from './flash';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { parseBoolean } from './lib/utils/common_utils';
|
||||
import { __ } from './locale';
|
||||
|
|
@ -27,7 +27,7 @@ export default () => {
|
|||
})
|
||||
.catch(() => {
|
||||
hideConsentMessage();
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: __('Something went wrong. Try again later.'),
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlToast, GlTooltipDirective, GlSafeHtmlDirective, GlModal } from '@gitlab/ui';
|
||||
import Vue from 'vue';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
|
||||
import { s__ } from '~/locale';
|
||||
import { updateUserStatus } from '~/rest_api';
|
||||
|
|
@ -89,7 +89,7 @@ export default {
|
|||
window.location.reload();
|
||||
},
|
||||
onUpdateFail() {
|
||||
createFlash({
|
||||
createAlert({
|
||||
message: s__(
|
||||
"SetStatusModal|Sorry, we weren't able to set your status. Please try again later.",
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
@import './pages/branches';
|
||||
@import './pages/colors';
|
||||
@import './pages/commits';
|
||||
@import './pages/deploy_keys';
|
||||
@import './pages/detail_page';
|
||||
@import './pages/events';
|
||||
@import './pages/groups';
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
.deploy-keys-title {
|
||||
padding-bottom: 2px;
|
||||
line-height: 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module Ci
|
||||
class AllJobsResolver < BaseResolver
|
||||
type ::Types::Ci::JobType.connection_type, null: true
|
||||
|
||||
argument :statuses, [::Types::Ci::JobStatusEnum],
|
||||
required: false,
|
||||
description: 'Filter jobs by status.'
|
||||
|
||||
def resolve(statuses: nil)
|
||||
::Ci::JobsFinder.new(current_user: current_user, params: { scope: statuses }).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,7 +4,7 @@ module Types
|
|||
module BranchProtections
|
||||
class MergeAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes
|
||||
graphql_name 'MergeAccessLevel'
|
||||
description 'Defines which user roles, users, or groups can merge into a protected branch.'
|
||||
description 'Represents the merge access level of a branch protection.'
|
||||
accepts ::ProtectedBranch::MergeAccessLevel
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ module Types
|
|||
module BranchProtections
|
||||
class PushAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes
|
||||
graphql_name 'PushAccessLevel'
|
||||
description 'Defines which user roles, users, or groups can push to a protected branch.'
|
||||
description 'Represents the push access level of a branch protection.'
|
||||
accepts ::ProtectedBranch::PushAccessLevel
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -154,6 +154,12 @@ module Types
|
|||
null: true,
|
||||
description: "Whether Gitpod is enabled in application settings."
|
||||
|
||||
field :jobs,
|
||||
::Types::Ci::JobType.connection_type,
|
||||
null: true,
|
||||
description: 'All jobs on this GitLab instance.',
|
||||
resolver: ::Resolvers::Ci::AllJobsResolver
|
||||
|
||||
def design_management
|
||||
DesignManagementObject.new(nil)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ module NavHelper
|
|||
end
|
||||
|
||||
def page_has_markdown?
|
||||
current_path?('merge_requests#show') ||
|
||||
current_path?('projects/merge_requests#show') ||
|
||||
current_path?('projects/merge_requests/conflicts#show') ||
|
||||
current_path?('issues#show') ||
|
||||
current_path?('milestones#show') ||
|
||||
|
|
|
|||
|
|
@ -225,6 +225,10 @@ class NotifyPreview < ActionMailer::Preview
|
|||
Notify.request_review_merge_request_email(user.id, merge_request.id, user.id).message
|
||||
end
|
||||
|
||||
def project_was_moved_email
|
||||
Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab").message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"properties": {
|
||||
"top_n": { "type": "number" },
|
||||
"version": { "type": "string" },
|
||||
"changes": { "type": "array" }
|
||||
"reviewers": { "type": "array" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,18 @@
|
|||
- @can_bulk_update = can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit)
|
||||
- @can_bulk_update = can?(current_user, :admin_merge_request, @group) && @group.licensed_feature_available?(:group_bulk_edit) && issuables_count_for_state(:merge_requests, :all) > 0
|
||||
|
||||
- page_title _("Merge requests")
|
||||
|
||||
- if issuables_count_for_state(:merge_requests, :all) == 0
|
||||
= render 'shared/issuable/search_bar', type: :merge_requests
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
- if current_user
|
||||
.nav-controls
|
||||
- if @can_bulk_update
|
||||
= render_if_exists 'projects/merge_requests/bulk_update_button'
|
||||
|
||||
= render 'shared/empty_states/merge_requests', project_select_button: true
|
||||
- else
|
||||
.top-area
|
||||
= render 'shared/issuable/nav', type: :merge_requests
|
||||
- if current_user
|
||||
.nav-controls
|
||||
- if @can_bulk_update
|
||||
= render_if_exists 'projects/merge_requests/bulk_update_button'
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: _("merge request"), type: :merge_requests, with_feature_enabled: 'merge_requests', with_shared: false, include_projects_in_subgroups: true
|
||||
|
||||
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: _("merge request"), type: :merge_requests, with_feature_enabled: 'merge_requests', with_shared: false, include_projects_in_subgroups: true
|
||||
= render 'shared/issuable/search_bar', type: :merge_requests
|
||||
- if @can_bulk_update
|
||||
= render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests
|
||||
|
||||
= render 'shared/issuable/search_bar', type: :merge_requests
|
||||
|
||||
- if @can_bulk_update
|
||||
= render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests
|
||||
|
||||
= render 'shared/merge_requests'
|
||||
= render 'shared/merge_requests'
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
- repo_url_styles = "background: #f5f5f5; padding:10px; border:1px solid #ddd"
|
||||
- ssh_url_to_repo = content_tag(:p, "git remote set-url origin #{strip_tags(@project.ssh_url_to_repo)}", style: repo_url_styles)
|
||||
- http_url_to_repo = content_tag(:p, "git remote set-url origin #{strip_tags(@project.http_url_to_repo)}", style: repo_url_styles)
|
||||
%p
|
||||
Project #{@old_path_with_namespace} was moved to another location
|
||||
= s_('Notify|Project %{old_path_with_namespace} was moved to another location.') % { old_path_with_namespace: @old_path_with_namespace }
|
||||
%p
|
||||
The project is now located under
|
||||
= link_to project_url(@project) do
|
||||
= @project.full_name
|
||||
%p
|
||||
To update the remote url in your local repository run (for ssh):
|
||||
%p{ style: "background: #f5f5f5; padding:10px; border:1px solid #ddd" }
|
||||
git remote set-url origin #{@project.ssh_url_to_repo}
|
||||
%p
|
||||
or for http(s):
|
||||
%p{ style: "background: #f5f5f5; padding:10px; border:1px solid #ddd" }
|
||||
git remote set-url origin #{@project.http_url_to_repo}
|
||||
%br
|
||||
- project_full_name_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: project_url(@project) }
|
||||
= html_escape(s_('Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}.')) % { project_full_name_link_start: project_full_name_link_start, link_end: '</a>'.html_safe, project_full_name: @project.full_name }
|
||||
= html_escape(s_('Notify|%{p_start}To update the remote url in your local repository run (for ssh):%{p_end} %{ssh_url_to_repo} %{p_start}or for http(s):%{p_end} %{http_url_to_repo}')) % { p_start: '<p>'.html_safe, p_end: '</p>'.html_safe, ssh_url_to_repo: ssh_url_to_repo, http_url_to_repo: http_url_to_repo }
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
%span.gl-ml-3.gl-mb-3
|
||||
= render 'shared/members/access_request_links', source: @project
|
||||
|
||||
= cache_if(cache_enabled, [@project, :buttons, current_user, @notification_setting], expires_in: 1.day) do
|
||||
= cache_if(cache_enabled, [@project, @project.star_count, @project.forks_count, :buttons, current_user, @notification_setting], expires_in: 1.day) do
|
||||
.project-repo-buttons.gl-display-flex.gl-justify-content-md-end.gl-align-items-start.gl-flex-wrap.gl-mt-5
|
||||
- if current_user
|
||||
- if current_user.admin?
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@
|
|||
= link_to new_project_fork_path(@project), class: "gl-button btn btn-default btn-sm fork-btn #{button_class}" do
|
||||
= sprite_icon('fork', css_class: 'icon')
|
||||
%span= s_('ProjectOverview|Fork')
|
||||
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: "gl-button btn btn-default btn-sm count has-tooltip #{count_class}" do
|
||||
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Forks'), s_('ProjectOverview|Forks'), @project.forks_count), class: "gl-button btn btn-default btn-sm count has-tooltip fork-count #{count_class}" do
|
||||
= @project.forks_count
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
- if @project.pages_deployed?
|
||||
- if can?(current_user, :remove_pages, @project)
|
||||
.card.border-danger
|
||||
.card-header.bg-danger.text-white
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'border-danger' }, header_options: {class: 'bg-danger text-white'}) do |c|
|
||||
- c.with_header do
|
||||
= s_('GitLabPages|Remove pages')
|
||||
.errors-holder
|
||||
.card-body
|
||||
%p.gl-mb-0
|
||||
= s_('GitLabPages|Removing pages will prevent them from being exposed to the outside world.')
|
||||
.card-footer
|
||||
= link_to s_('GitLabPages|Remove pages'), project_pages_path(@project), data: { confirm: s_('GitLabPages|Are you sure?'), 'confirm-btn-variant': 'danger'}, method: :delete, class: "btn gl-button btn-danger", "aria-label": s_('GitLabPages|Remove pages')
|
||||
- c.with_body do
|
||||
= s_('GitLabPages|Removing pages will prevent them from being exposed to the outside world.')
|
||||
- c.with_footer do
|
||||
= render Pajamas::ButtonComponent.new(href: project_pages_path(@project),
|
||||
variant: :danger,
|
||||
method: :delete,
|
||||
button_options: {data: { confirm: s_('GitLabPages|Are you sure?'), 'confirm-btn-variant': 'danger'}, "aria-label": s_('GitLabPages|Remove pages')}) do
|
||||
= s_('GitLabPages|Remove pages')
|
||||
- else
|
||||
.nothing-here-block
|
||||
= s_('GitLabPages|Only project maintainers can remove pages')
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%section.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings.expanded{ class: [('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)], data: { qa_selector: 'merge_request_settings_content' } }
|
||||
.settings-header
|
||||
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Merge requests')
|
||||
%h4= _('Merge requests')
|
||||
= render_if_exists 'projects/merge_request_settings_description_text'
|
||||
|
||||
.settings-content
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
- if project.creator && use_creator_avatar
|
||||
= render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '', class: 'gl-mr-5')
|
||||
- else
|
||||
= project_icon(project, alt: '', class: 'avatar project-avatar s48', width: 48, height: 48)
|
||||
= render Pajamas::AvatarComponent.new(project, size: 48, alt: '', class: 'gl-mr-5')
|
||||
.project-details.d-sm-flex.flex-sm-fill.align-items-center{ data: { qa_selector: 'project_content', qa_project_name: project.name } }
|
||||
.flex-wrapper
|
||||
.d-flex.align-items-center.flex-wrap.project-title
|
||||
|
|
|
|||
|
|
@ -226,6 +226,22 @@ Returns [`Iteration`](#iteration).
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="queryiterationid"></a>`id` | [`IterationID!`](#iterationid) | Find an iteration by its ID. |
|
||||
|
||||
### `Query.jobs`
|
||||
|
||||
All jobs on this GitLab instance.
|
||||
|
||||
Returns [`CiJobConnection`](#cijobconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="queryjobsstatuses"></a>`statuses` | [`[CiJobStatus!]`](#cijobstatus) | Filter jobs by status. |
|
||||
|
||||
### `Query.licenseHistoryEntries`
|
||||
|
||||
Fields related to entries in the license history.
|
||||
|
|
@ -9322,29 +9338,6 @@ The edge type for [`TreeEntry`](#treeentry).
|
|||
| <a id="treeentryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="treeentryedgenode"></a>`node` | [`TreeEntry`](#treeentry) | The item at the end of the edge. |
|
||||
|
||||
#### `UnprotectAccessLevelConnection`
|
||||
|
||||
The connection type for [`UnprotectAccessLevel`](#unprotectaccesslevel).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="unprotectaccesslevelconnectionedges"></a>`edges` | [`[UnprotectAccessLevelEdge]`](#unprotectaccessleveledge) | A list of edges. |
|
||||
| <a id="unprotectaccesslevelconnectionnodes"></a>`nodes` | [`[UnprotectAccessLevel]`](#unprotectaccesslevel) | A list of nodes. |
|
||||
| <a id="unprotectaccesslevelconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `UnprotectAccessLevelEdge`
|
||||
|
||||
The edge type for [`UnprotectAccessLevel`](#unprotectaccesslevel).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="unprotectaccessleveledgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="unprotectaccessleveledgenode"></a>`node` | [`UnprotectAccessLevel`](#unprotectaccesslevel) | The item at the end of the edge. |
|
||||
|
||||
#### `UploadRegistryConnection`
|
||||
|
||||
The connection type for [`UploadRegistry`](#uploadregistry).
|
||||
|
|
@ -10227,7 +10220,6 @@ Branch protection details for a branch rule.
|
|||
| <a id="branchprotectioncodeownerapprovalrequired"></a>`codeOwnerApprovalRequired` | [`Boolean!`](#boolean) | Enforce code owner approvals before allowing a merge. |
|
||||
| <a id="branchprotectionmergeaccesslevels"></a>`mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when this branch is the source branch. (see [Connections](#connections)) |
|
||||
| <a id="branchprotectionpushaccesslevels"></a>`pushAccessLevels` | [`PushAccessLevelConnection`](#pushaccesslevelconnection) | Details about who can push when this branch is the source branch. (see [Connections](#connections)) |
|
||||
| <a id="branchprotectionunprotectaccesslevels"></a>`unprotectAccessLevels` | [`UnprotectAccessLevelConnection`](#unprotectaccesslevelconnection) | Details about who can unprotect this branch. (see [Connections](#connections)) |
|
||||
|
||||
### `BranchRule`
|
||||
|
||||
|
|
@ -13961,7 +13953,7 @@ Maven metadata.
|
|||
|
||||
### `MergeAccessLevel`
|
||||
|
||||
Defines which user roles, users, or groups can merge into a protected branch.
|
||||
Represents the merge access level of a branch protection.
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
@ -17369,7 +17361,7 @@ Which group, user or role is allowed to execute deployments to the environment.
|
|||
|
||||
### `PushAccessLevel`
|
||||
|
||||
Defines which user roles, users, or groups can push to a protected branch.
|
||||
Represents the push access level of a branch protection.
|
||||
|
||||
#### Fields
|
||||
|
||||
|
|
@ -18598,19 +18590,6 @@ Represents a directory.
|
|||
| <a id="treeentrywebpath"></a>`webPath` | [`String`](#string) | Web path for the tree entry (directory). |
|
||||
| <a id="treeentryweburl"></a>`webUrl` | [`String`](#string) | Web URL for the tree entry (directory). |
|
||||
|
||||
### `UnprotectAccessLevel`
|
||||
|
||||
Defines which user roles, users, or groups can unprotect a protected branch.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="unprotectaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
|
||||
| <a id="unprotectaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
|
||||
| <a id="unprotectaccesslevelgroup"></a>`group` | [`Group`](#group) | Group associated with this access level. |
|
||||
| <a id="unprotectaccessleveluser"></a>`user` | [`UserCore`](#usercore) | User associated with this access level. |
|
||||
|
||||
### `UploadRegistry`
|
||||
|
||||
Represents the Geo replication and verification state of an upload.
|
||||
|
|
|
|||
|
|
@ -22,14 +22,9 @@ To enable the Bitbucket OmniAuth provider you must register your application
|
|||
with Bitbucket.org. Bitbucket generates an application ID and secret key for
|
||||
you to use.
|
||||
|
||||
WARNING:
|
||||
To help prevent an [OAuth 2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/)
|
||||
vulnerability in which users' GitLab accounts could be compromised, append `/users/auth`
|
||||
to the end of the Bitbucket authorization callback URL.
|
||||
|
||||
1. Sign in to [Bitbucket.org](https://bitbucket.org).
|
||||
1. Navigate to your individual user settings (**Bitbucket settings**) or a team's
|
||||
settings (**Manage team**), depending on how you want the application registered.
|
||||
1. Go to your individual user settings (**Bitbucket settings**) or a team's
|
||||
settings (**Manage team**), depending on how you want to register the application.
|
||||
It does not matter if the application is registered as an individual or a
|
||||
team, that is entirely up to you.
|
||||
1. In the left menu under **Access Management**, select **OAuth**.
|
||||
|
|
@ -44,6 +39,12 @@ to the end of the Bitbucket authorization callback URL.
|
|||
`https://gitlab.example.com/users/auth`.
|
||||
Leaving this field empty
|
||||
[results in an `Invalid redirect_uri` message](https://confluence.atlassian.com/bitbucket/oauth-faq-338365710.html).
|
||||
|
||||
WARNING:
|
||||
To help prevent an [OAuth 2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/)
|
||||
vulnerability in which users' GitLab accounts could be compromised, append `/users/auth`
|
||||
to the end of the Bitbucket authorization callback URL.
|
||||
|
||||
- **URL:** The URL to your GitLab installation, such as `https://gitlab.example.com`.
|
||||
|
||||
1. Grant at least the following permissions:
|
||||
|
|
@ -85,8 +86,8 @@ to the end of the Bitbucket authorization callback URL.
|
|||
{
|
||||
name: "bitbucket",
|
||||
# label: "Provider name", # optional label for login button, defaults to "Bitbucket"
|
||||
app_id: "BITBUCKET_APP_KEY",
|
||||
app_secret: "BITBUCKET_APP_SECRET",
|
||||
app_id: "<bitbucket_app_key>",
|
||||
app_secret: "<bitbucket_app_secret>",
|
||||
url: "https://bitbucket.org/"
|
||||
}
|
||||
]
|
||||
|
|
@ -100,12 +101,12 @@ to the end of the Bitbucket authorization callback URL.
|
|||
providers:
|
||||
- { name: 'bitbucket',
|
||||
# label: 'Provider name', # optional label for login button, defaults to "Bitbucket"
|
||||
app_id: 'BITBUCKET_APP_KEY',
|
||||
app_secret: 'BITBUCKET_APP_SECRET',
|
||||
app_id: '<bitbucket_app_key>',
|
||||
app_secret: '<bitbucket_app_secret>',
|
||||
url: 'https://bitbucket.org/' }
|
||||
```
|
||||
|
||||
Where `BITBUCKET_APP_KEY` is the Key and `BITBUCKET_APP_SECRET` the Secret
|
||||
Where `<bitbucket_app_key>` is the **Key** and `<bitbucket_app_secret>` the **Secret**
|
||||
from the Bitbucket application page.
|
||||
|
||||
1. Save the configuration file.
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Epics **(PREMIUM)**
|
||||
|
||||
> Single-level epics were [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) from GitLab Ultimate to GitLab Premium in 12.8.
|
||||
When [issues](../../project/issues/index.md) share a theme across projects and
|
||||
milestones, you can manage them by using epics.
|
||||
|
||||
When [issues](../../project/issues/index.md) share a theme across projects and milestones,
|
||||
you can manage them by using epics.
|
||||
|
||||
You can also create child epics, and assign start and end dates,
|
||||
which creates a visual roadmap for you to view progress.
|
||||
You can also create child epics and assign start and end dates, which creates
|
||||
a visual roadmap for you to view progress.
|
||||
|
||||
Use epics:
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ module Gitlab
|
|||
store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupTransferedEvent
|
||||
store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupPathChangedEvent
|
||||
store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::Groups::GroupDeletedEvent
|
||||
store.subscribe ::Pages::InvalidateDomainCacheWorker, to: ::PagesDomains::PagesDomainDeletedEvent
|
||||
|
||||
store.subscribe ::MergeRequests::CreateApprovalEventWorker, to: ::MergeRequests::ApprovedEvent
|
||||
store.subscribe ::MergeRequests::CreateApprovalNoteWorker, to: ::MergeRequests::ApprovedEvent
|
||||
|
|
|
|||
|
|
@ -27248,6 +27248,9 @@ msgstr ""
|
|||
msgid "Notify|%{name} requested a new review on %{mr_link}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|%{p_start}To update the remote url in your local repository run (for ssh):%{p_end} %{ssh_url_to_repo} %{p_start}or for http(s):%{p_end} %{http_url_to_repo}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|%{paragraph_start}Hi %{name}!%{paragraph_end} %{paragraph_start}A new public key was added to your account:%{paragraph_end} %{paragraph_start}title: %{key_title}%{paragraph_end} %{paragraph_start}If this key was added in error, you can remove it under %{removal_link}%{paragraph_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27383,6 +27386,9 @@ msgstr ""
|
|||
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|Project %{project_name} was exported successfully."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27404,6 +27410,9 @@ msgstr ""
|
|||
msgid "Notify|The download link will expire in 24 hours."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify|The push did not contain any new commits, but force pushed to delete the commits and changes below."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -48,8 +48,9 @@ module QA
|
|||
usage_quota.purchase_more_storage
|
||||
end
|
||||
|
||||
# Purchase checkout opens a new tab
|
||||
Chemlab.configuration.browser.session.engine.switch_window
|
||||
# Purchase checkout opens a new tab but buying additional storage does not
|
||||
session = Chemlab.configuration.browser.session.engine
|
||||
session.switch_window if session.windows.size == 2
|
||||
|
||||
Gitlab::Page::Subscriptions::New.perform do |storage|
|
||||
storage.quantity = quantity
|
||||
|
|
|
|||
|
|
@ -39,43 +39,23 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :no_one_can_merge do
|
||||
transient do
|
||||
default_merge_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
|
||||
end
|
||||
end
|
||||
|
||||
trait :developers_can_merge do
|
||||
transient do
|
||||
default_merge_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
|
||||
end
|
||||
end
|
||||
|
||||
trait :maintainers_can_merge do
|
||||
transient do
|
||||
default_merge_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
|
||||
end
|
||||
end
|
||||
|
||||
trait :no_one_can_push do
|
||||
trait :maintainers_can_push do
|
||||
transient do
|
||||
default_push_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
|
||||
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
|
||||
end
|
||||
end
|
||||
|
||||
trait :maintainers_can_merge do
|
||||
transient do
|
||||
default_push_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -89,13 +69,33 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :maintainers_can_push do
|
||||
trait :developers_can_merge do
|
||||
transient do
|
||||
default_merge_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
|
||||
end
|
||||
end
|
||||
|
||||
trait :no_one_can_push do
|
||||
transient do
|
||||
default_push_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
|
||||
protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
|
||||
end
|
||||
end
|
||||
|
||||
trait :no_one_can_merge do
|
||||
transient do
|
||||
default_merge_level { false }
|
||||
end
|
||||
|
||||
after(:build) do |protected_branch|
|
||||
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -94,9 +94,7 @@ RSpec.describe 'Group empty states' do
|
|||
end
|
||||
|
||||
it "shows a new #{issuable_name} button" do
|
||||
within '.empty-state' do
|
||||
expect(page).to have_content("create #{issuable_name}")
|
||||
end
|
||||
expect(page).to have_content("create #{issuable_name}")
|
||||
end
|
||||
|
||||
it "the new #{issuable_name} button opens a project dropdown" do
|
||||
|
|
|
|||
|
|
@ -57,6 +57,16 @@ RSpec.describe 'Group merge requests page' do
|
|||
expect(find('#js-dropdown-assignee .filter-dropdown')).to have_content(user.name)
|
||||
expect(find('#js-dropdown-assignee .filter-dropdown')).not_to have_content(user2.name)
|
||||
end
|
||||
|
||||
it 'will still show the navbar with no results' do
|
||||
search_term = 'some-search-term-that-produces-zero-results'
|
||||
|
||||
filtered_search.set(search_term)
|
||||
filtered_search.send_keys(:enter)
|
||||
|
||||
expect(page).to have_content('filter produced no results')
|
||||
expect(page).to have_link('Open', href: "/groups/#{group.name}/-/merge_requests?scope=all&search=#{search_term}&state=opened")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'new merge request dropdown' do
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let(:merge_request_in_only_mwps_project) { create(:merge_request, source_project: project_only_mwps) }
|
||||
|
||||
def click_expand_button
|
||||
find('[data-testid="report-section-expand-button"]').click
|
||||
end
|
||||
|
||||
before do
|
||||
project.add_maintainer(user)
|
||||
project_only_mwps.add_maintainer(user)
|
||||
|
|
@ -606,7 +610,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the new failure' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 failed out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -621,7 +625,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the new failure' do
|
||||
it 'shows the test report detail' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'addTest'
|
||||
|
|
@ -654,7 +658,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the existing failure' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 failed out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -668,7 +672,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the existing failure' do
|
||||
it 'shows test report detail of it' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'Test#sum when a is 1 and b is 3 returns summary'
|
||||
|
|
@ -701,7 +705,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the resolved failure' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 fixed test result out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -715,7 +719,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the resolved failure' do
|
||||
it 'shows test report detail of it' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'addTest'
|
||||
|
|
@ -747,7 +751,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the new error' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 error out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -762,7 +766,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the new error' do
|
||||
it 'shows the test report detail' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'addTest'
|
||||
|
|
@ -794,7 +798,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the existing error' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 error out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -808,7 +812,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the existing error' do
|
||||
it 'shows test report detail of it' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'Test#sum when a is 4 and b is 4 returns summary'
|
||||
|
|
@ -840,7 +844,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the resolved error' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 fixed test result out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
@ -854,7 +858,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
context 'when user clicks the resolved error' do
|
||||
it 'shows test report detail of it' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
within(".js-report-section-container") do
|
||||
click_button 'addTest'
|
||||
|
|
@ -894,7 +898,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
|
|||
|
||||
it 'shows test reports summary which includes the resolved failure' do
|
||||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
click_expand_button
|
||||
|
||||
expect(page).to have_content('Test summary contained 20 failed out of 20 total tests')
|
||||
within(".js-report-section-container") do
|
||||
|
|
|
|||
|
|
@ -118,17 +118,28 @@ RSpec.describe 'Project fork' do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples "increments the fork counter on the source project's page" do
|
||||
specify :sidekiq_might_not_need_inline do
|
||||
create_forks
|
||||
|
||||
visit project_path(project)
|
||||
|
||||
expect(page).to have_css('.fork-count', text: 2)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'fork button on project page'
|
||||
it_behaves_like 'create fork page', 'Fork project'
|
||||
|
||||
context 'fork form', :js do
|
||||
let(:group) { create(:group) }
|
||||
let(:group2) { create(:group) }
|
||||
let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
|
||||
|
||||
def submit_form
|
||||
def submit_form(group_obj = group)
|
||||
find('[data-testid="select_namespace_dropdown"]').click
|
||||
find('[data-testid="select_namespace_dropdown_search_field"]').fill_in(with: group.name)
|
||||
click_button group.name
|
||||
find('[data-testid="select_namespace_dropdown_search_field"]').fill_in(with: group_obj.name)
|
||||
click_button group_obj.name
|
||||
|
||||
click_button 'Fork project'
|
||||
end
|
||||
|
|
@ -166,5 +177,41 @@ RSpec.describe 'Project fork' do
|
|||
expect(page).to have_content("#{group.name} / #{fork_name}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cache_home_panel feature flag' do
|
||||
before do
|
||||
create(:group_member, :maintainer, user: user, group: group2 )
|
||||
end
|
||||
|
||||
context 'when caching is enabled' do
|
||||
before do
|
||||
stub_feature_flags(cache_home_panel: project)
|
||||
end
|
||||
|
||||
it_behaves_like "increments the fork counter on the source project's page"
|
||||
end
|
||||
|
||||
context 'when caching is disabled' do
|
||||
before do
|
||||
stub_feature_flags(cache_home_panel: false)
|
||||
end
|
||||
|
||||
it_behaves_like "increments the fork counter on the source project's page"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_fork(group_obj = group)
|
||||
visit project_path(project)
|
||||
find('.fork-btn').click
|
||||
submit_form(group_obj)
|
||||
wait_for_requests
|
||||
end
|
||||
|
||||
def create_forks
|
||||
create_fork
|
||||
create_fork(group2)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ RSpec.describe 'Projects > Show > User interacts with project stars' do
|
|||
visit(project_path(project))
|
||||
end
|
||||
|
||||
it 'retains the star count even after a page reload' do
|
||||
star_project
|
||||
|
||||
reload_page
|
||||
|
||||
expect(page).to have_css('.star-count', text: 1)
|
||||
end
|
||||
|
||||
it 'toggles the star' do
|
||||
star_project
|
||||
|
||||
|
|
@ -63,6 +71,10 @@ end
|
|||
|
||||
private
|
||||
|
||||
def reload_page
|
||||
visit current_path
|
||||
end
|
||||
|
||||
def star_project
|
||||
click_button(_('Star'))
|
||||
wait_for_requests
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@ import ReportSection from '~/reports/components/report_section.vue';
|
|||
describe('ReportSection component', () => {
|
||||
let wrapper;
|
||||
|
||||
const findButton = () => wrapper.findComponent(GlButton);
|
||||
const findExpandButton = () => wrapper.findComponent(GlButton);
|
||||
const findPopover = () => wrapper.findComponent(HelpPopover);
|
||||
const findReportSection = () => wrapper.find('.js-report-section-container');
|
||||
const expectExpandButtonOpen = () =>
|
||||
expect(findExpandButton().props('icon')).toBe('chevron-lg-up');
|
||||
const expectExpandButtonClosed = () =>
|
||||
expect(findExpandButton().props('icon')).toBe('chevron-lg-down');
|
||||
|
||||
const resolvedIssues = [
|
||||
{
|
||||
|
|
@ -122,22 +126,22 @@ describe('ReportSection component', () => {
|
|||
it('toggles issues', async () => {
|
||||
createComponent({ props: { hasIssues: true } });
|
||||
|
||||
await findButton().trigger('click');
|
||||
await findExpandButton().trigger('click');
|
||||
|
||||
expect(findReportSection().isVisible()).toBe(true);
|
||||
expect(findButton().text()).toBe('Collapse');
|
||||
expectExpandButtonOpen();
|
||||
|
||||
await findButton().trigger('click');
|
||||
await findExpandButton().trigger('click');
|
||||
|
||||
expect(findReportSection().isVisible()).toBe(false);
|
||||
expect(findButton().text()).toBe('Expand');
|
||||
expectExpandButtonClosed();
|
||||
});
|
||||
|
||||
it('is always expanded, if always-open is set to true', () => {
|
||||
createComponent({ props: { hasIssues: true, alwaysOpen: true } });
|
||||
|
||||
expect(findReportSection().isVisible()).toBe(true);
|
||||
expect(findButton().exists()).toBe(false);
|
||||
expect(findExpandButton().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -148,7 +152,7 @@ describe('ReportSection component', () => {
|
|||
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
|
||||
findButton().trigger('click');
|
||||
findExpandButton().trigger('click');
|
||||
|
||||
expect(wrapper.emitted('toggleEvent')).toEqual([[]]);
|
||||
});
|
||||
|
|
@ -158,7 +162,7 @@ describe('ReportSection component', () => {
|
|||
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
|
||||
findButton().trigger('click');
|
||||
findExpandButton().trigger('click');
|
||||
|
||||
expect(wrapper.emitted('toggleEvent')).toBeUndefined();
|
||||
});
|
||||
|
|
@ -208,7 +212,7 @@ describe('ReportSection component', () => {
|
|||
});
|
||||
|
||||
it('should still render the expand/collapse button', () => {
|
||||
expect(findButton().text()).toBe('Expand');
|
||||
expectExpandButtonClosed();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { loadCommits, isRequested, resetRequestedCommits } from '~/repository/commits_service';
|
||||
import httpStatus from '~/lib/utils/http_status';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import { I18N_COMMIT_DATA_FETCH_ERROR } from '~/repository/constants';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
|
@ -65,13 +65,13 @@ describe('commits service', () => {
|
|||
expect(isRequested(300)).toBe(false);
|
||||
});
|
||||
|
||||
it('calls `createFlash` when the request fails', async () => {
|
||||
it('calls `createAlert` when the request fails', async () => {
|
||||
const invalidPath = '/#@ some/path';
|
||||
const invalidUrl = `${url}${invalidPath}`;
|
||||
mock.onGet(invalidUrl).replyOnce(httpStatus.INTERNAL_SERVER_ERROR, [], {});
|
||||
|
||||
await requestCommits(1, 'my-project', invalidPath);
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({ message: I18N_COMMIT_DATA_FETCH_ERROR });
|
||||
expect(createAlert).toHaveBeenCalledWith({ message: I18N_COMMIT_DATA_FETCH_ERROR });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { nextTick } from 'vue';
|
|||
import axios from 'axios';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import NewDirectoryModal from '~/repository/components/new_directory_modal.vue';
|
||||
|
|
@ -194,7 +194,7 @@ describe('NewDirectoryModal', () => {
|
|||
await fillForm({ dirName: 'foo', branchName: 'master', commitMessage: 'foo' });
|
||||
await submitForm();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: NewDirectoryModal.i18n.ERROR_MESSAGE,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import axios from 'axios';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import httpStatusCodes from '~/lib/utils/http_status';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
|
||||
|
|
@ -185,7 +185,7 @@ describe('UploadBlobModal', () => {
|
|||
});
|
||||
|
||||
it('creates a flash error', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: 'Error uploading file. Please try again.',
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import testAction from 'helpers/vuex_action_helper';
|
||||
import Api from '~/api';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import * as urlUtils from '~/lib/utils/url_utility';
|
||||
import * as actions from '~/search/store/actions';
|
||||
|
|
@ -37,8 +37,8 @@ describe('Global Search Store Actions', () => {
|
|||
let state;
|
||||
|
||||
const flashCallback = (callCount) => {
|
||||
expect(createFlash).toHaveBeenCalledTimes(callCount);
|
||||
createFlash.mockClear();
|
||||
expect(createAlert).toHaveBeenCalledTimes(callCount);
|
||||
createAlert.mockClear();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import { initEmojiMock, clearEmojiMock } from 'helpers/emoji';
|
||||
import * as UserApi from '~/api/user_api';
|
||||
import EmojiPicker from '~/emoji/components/picker.vue';
|
||||
import createFlash from '~/flash';
|
||||
import { createAlert } from '~/flash';
|
||||
import stubChildren from 'helpers/stub_children';
|
||||
import SetStatusModalWrapper from '~/set_status_modal/set_status_modal_wrapper.vue';
|
||||
import { AVAILABILITY_STATUS } from '~/set_status_modal/constants';
|
||||
|
|
@ -253,7 +253,7 @@ describe('SetStatusModalWrapper', () => {
|
|||
findModal().vm.$emit('primary');
|
||||
await nextTick();
|
||||
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
expect(createAlert).toHaveBeenCalledWith({
|
||||
message: "Sorry, we weren't able to set your status. Please try again later.",
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::Ci::AllJobsResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:successful_job) { create(:ci_build, :success, name: 'Job One') }
|
||||
let_it_be(:successful_job_two) { create(:ci_build, :success, name: 'Job Two') }
|
||||
let_it_be(:failed_job) { create(:ci_build, :failed, name: 'Job Three') }
|
||||
let_it_be(:pending_job) { create(:ci_build, :pending, name: 'Job Three') }
|
||||
|
||||
let(:args) { {} }
|
||||
let(:current_user) { create(:admin) }
|
||||
|
||||
subject { resolve_jobs(args) }
|
||||
|
||||
describe '#resolve' do
|
||||
context 'with authorized user' do
|
||||
context 'with statuses argument' do
|
||||
let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } }
|
||||
|
||||
it { is_expected.to contain_exactly(successful_job, successful_job_two) }
|
||||
end
|
||||
|
||||
context 'with multiple statuses' do
|
||||
let(:args) do
|
||||
{ statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS'),
|
||||
Types::Ci::JobStatusEnum.coerce_isolated_input('FAILED')] }
|
||||
end
|
||||
|
||||
it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job) }
|
||||
end
|
||||
|
||||
context 'without statuses argument' do
|
||||
it { is_expected.to contain_exactly(successful_job, successful_job_two, failed_job, pending_job) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unauthorized user' do
|
||||
let(:current_user) { nil }
|
||||
|
||||
it { is_expected.to be_empty }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resolve_jobs(args = {}, context = { current_user: current_user })
|
||||
resolve(described_class, args: args, ctx: context)
|
||||
end
|
||||
end
|
||||
|
|
@ -116,7 +116,7 @@ RSpec.describe NavHelper do
|
|||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where path: %w(
|
||||
merge_requests#show
|
||||
projects/merge_requests#show
|
||||
projects/merge_requests/conflicts#show
|
||||
issues#show
|
||||
milestones#show
|
||||
|
|
|
|||
|
|
@ -118,9 +118,10 @@ RSpec.describe Gitlab::GithubImport::Importer::LfsObjectsImporter do
|
|||
expect(service).to receive(:execute).and_return([lfs_download_object])
|
||||
end
|
||||
|
||||
expect(Gitlab::GithubImport::ImportLfsObjectWorker).to receive(:bulk_perform_in).with(1.second, [
|
||||
[project.id, an_instance_of(Hash), an_instance_of(String)]
|
||||
], batch_size: 1000, batch_delay: 1.minute)
|
||||
expect(Gitlab::GithubImport::ImportLfsObjectWorker).to receive(:bulk_perform_in)
|
||||
.with(1.second, [
|
||||
[project.id, an_instance_of(Hash), an_instance_of(String)]
|
||||
], batch_size: 1000, batch_delay: 1.minute)
|
||||
|
||||
waiter = importer.parallel_import
|
||||
|
||||
|
|
|
|||
|
|
@ -83,9 +83,10 @@ RSpec.describe Gitlab::GithubImport::Importer::NotesImporter do
|
|||
.to receive(:each_object_to_import)
|
||||
.and_yield(github_comment)
|
||||
|
||||
expect(Gitlab::GithubImport::ImportNoteWorker).to receive(:bulk_perform_in).with(1.second, [
|
||||
[project.id, an_instance_of(Hash), an_instance_of(String)]
|
||||
], batch_size: 1000, batch_delay: 1.minute)
|
||||
expect(Gitlab::GithubImport::ImportNoteWorker).to receive(:bulk_perform_in)
|
||||
.with(1.second, [
|
||||
[project.id, an_instance_of(Hash), an_instance_of(String)]
|
||||
], batch_size: 1000, batch_delay: 1.minute)
|
||||
|
||||
waiter = importer.parallel_import
|
||||
|
||||
|
|
|
|||
|
|
@ -295,11 +295,12 @@ RSpec.describe Gitlab::GithubImport::ParallelScheduling do
|
|||
end
|
||||
|
||||
it 'imports data in parallel batches with delays' do
|
||||
expect(worker_class).to receive(:bulk_perform_in).with(1.second, [
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)],
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)],
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)]
|
||||
], batch_size: batch_size, batch_delay: batch_delay)
|
||||
expect(worker_class).to receive(:bulk_perform_in)
|
||||
.with(1.second, [
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)],
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)],
|
||||
[project.id, { title: 'Foo' }, an_instance_of(String)]
|
||||
], batch_size: batch_size, batch_delay: batch_delay)
|
||||
|
||||
importer.parallel_import
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,10 +43,11 @@ RSpec.describe Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp do
|
|||
it 're-formats the params hash' do
|
||||
params = result['params']
|
||||
|
||||
expect(params).to eq([
|
||||
{ 'key' => 'description', 'value' => '[FILTERED]' },
|
||||
{ 'key' => 'name', 'value' => 'gitlab test' },
|
||||
{ 'key' => 'int', 'value' => 42 }
|
||||
])
|
||||
expect(params).to eq(
|
||||
[
|
||||
{ 'key' => 'description', 'value' => '[FILTERED]' },
|
||||
{ 'key' => 'name', 'value' => 'gitlab test' },
|
||||
{ 'key' => 'int', 'value' => 42 }
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ RSpec.describe Gitlab::HookData::ReleaseBuilder do
|
|||
|
||||
it 'includes safe attribute' do
|
||||
%w[
|
||||
id
|
||||
created_at
|
||||
description
|
||||
name
|
||||
released_at
|
||||
tag
|
||||
id
|
||||
created_at
|
||||
description
|
||||
name
|
||||
released_at
|
||||
tag
|
||||
].each do |key|
|
||||
expect(data).to include(key)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -116,15 +116,15 @@ RSpec.describe Gitlab::ImportExport::Group::TreeRestorer do
|
|||
|
||||
shared_examples 'excluded attributes' do
|
||||
excluded_attributes = %w[
|
||||
id
|
||||
parent_id
|
||||
owner_id
|
||||
created_at
|
||||
updated_at
|
||||
runners_token
|
||||
runners_token_encrypted
|
||||
saml_discovery_token
|
||||
]
|
||||
id
|
||||
parent_id
|
||||
owner_id
|
||||
created_at
|
||||
updated_at
|
||||
runners_token
|
||||
runners_token_encrypted
|
||||
saml_discovery_token
|
||||
]
|
||||
|
||||
before do
|
||||
group.add_owner(importer_user)
|
||||
|
|
|
|||
|
|
@ -51,11 +51,12 @@ RSpec.describe Gitlab::ImportExport::Group::TreeSaver do
|
|||
.map { |line| Integer(line) }
|
||||
|
||||
expect(groups_catalog.size).to eq(3)
|
||||
expect(groups_catalog).to eq([
|
||||
group.id,
|
||||
group.descendants.first.id,
|
||||
group.descendants.first.descendants.first.id
|
||||
])
|
||||
expect(groups_catalog).to eq(
|
||||
[
|
||||
group.id,
|
||||
group.descendants.first.id,
|
||||
group.descendants.first.descendants.first.id
|
||||
])
|
||||
end
|
||||
|
||||
it 'has a file per group' do
|
||||
|
|
|
|||
|
|
@ -140,13 +140,13 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
|
|||
|
||||
it 'restores pipelines based on ascending id order' do
|
||||
expected_ordered_shas = %w[
|
||||
2ea1f3dec713d940208fb5ce4a38765ecb5d3f73
|
||||
ce84140e8b878ce6e7c4d298c7202ff38170e3ac
|
||||
048721d90c449b244b7b4c53a9186b04330174ec
|
||||
sha-notes
|
||||
5f923865dde3436854e9ceb9cdb7815618d4e849
|
||||
d2d430676773caa88cdaf7c55944073b2fd5561a
|
||||
2ea1f3dec713d940208fb5ce4a38765ecb5d3f73
|
||||
2ea1f3dec713d940208fb5ce4a38765ecb5d3f73
|
||||
ce84140e8b878ce6e7c4d298c7202ff38170e3ac
|
||||
048721d90c449b244b7b4c53a9186b04330174ec
|
||||
sha-notes
|
||||
5f923865dde3436854e9ceb9cdb7815618d4e849
|
||||
d2d430676773caa88cdaf7c55944073b2fd5561a
|
||||
2ea1f3dec713d940208fb5ce4a38765ecb5d3f73
|
||||
]
|
||||
|
||||
project = Project.find_by_path('project')
|
||||
|
|
|
|||
|
|
@ -51,13 +51,14 @@ RSpec.describe Gitlab::Kubernetes::RolloutInstances do
|
|||
end
|
||||
|
||||
it 'returns instances when there are two stable deployments' do
|
||||
deployments, pods = setup([
|
||||
kube_deployment(name: 'one', track: 'stable', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'stable', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'stable'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'stable')
|
||||
])
|
||||
deployments, pods = setup(
|
||||
[
|
||||
kube_deployment(name: 'one', track: 'stable', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'stable', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'stable'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'stable')
|
||||
])
|
||||
rollout_instances = described_class.new(deployments, pods)
|
||||
|
||||
expect(rollout_instances.pod_instances).to eq([{
|
||||
|
|
@ -76,13 +77,14 @@ RSpec.describe Gitlab::Kubernetes::RolloutInstances do
|
|||
end
|
||||
|
||||
it 'returns instances for two deployments with different tracks' do
|
||||
deployments, pods = setup([
|
||||
kube_deployment(name: 'one', track: 'mytrack', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'othertrack', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'mytrack'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'othertrack')
|
||||
])
|
||||
deployments, pods = setup(
|
||||
[
|
||||
kube_deployment(name: 'one', track: 'mytrack', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'othertrack', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'mytrack'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'othertrack')
|
||||
])
|
||||
rollout_instances = described_class.new(deployments, pods)
|
||||
|
||||
expect(rollout_instances.pod_instances).to eq([{
|
||||
|
|
@ -101,13 +103,14 @@ RSpec.describe Gitlab::Kubernetes::RolloutInstances do
|
|||
end
|
||||
|
||||
it 'sorts stable tracks after canary tracks' do
|
||||
deployments, pods = setup([
|
||||
kube_deployment(name: 'one', track: 'stable', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'canary', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'stable'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'canary')
|
||||
])
|
||||
deployments, pods = setup(
|
||||
[
|
||||
kube_deployment(name: 'one', track: 'stable', replicas: 1),
|
||||
kube_deployment(name: 'two', track: 'canary', replicas: 1)
|
||||
], [
|
||||
kube_pod(name: 'one', status: 'Running', track: 'stable'),
|
||||
kube_pod(name: 'two', status: 'Running', track: 'canary')
|
||||
])
|
||||
rollout_instances = described_class.new(deployments, pods)
|
||||
|
||||
expect(rollout_instances.pod_instances).to eq([{
|
||||
|
|
|
|||
|
|
@ -132,11 +132,12 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
|
|||
end
|
||||
|
||||
it "rejects bad params for arrays containing hashes with string values" do
|
||||
env = env_for(name: [
|
||||
{
|
||||
inner_key: "I am #{problematic_input} bad"
|
||||
}
|
||||
])
|
||||
env = env_for(
|
||||
name: [
|
||||
{
|
||||
inner_key: "I am #{problematic_input} bad"
|
||||
}
|
||||
])
|
||||
|
||||
expect(subject.call(env)).to eq error_400
|
||||
end
|
||||
|
|
@ -148,11 +149,12 @@ RSpec.describe Gitlab::Middleware::HandleMalformedStrings do
|
|||
it_behaves_like 'checks params'
|
||||
|
||||
it "gives up and does not reject too deeply nested params" do
|
||||
env = env_for(name: [
|
||||
{
|
||||
inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{problematic_input} bad" }] }
|
||||
}
|
||||
])
|
||||
env = env_for(
|
||||
name: [
|
||||
{
|
||||
inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{problematic_input} bad" }] }
|
||||
}
|
||||
])
|
||||
|
||||
expect(subject.call(env)).not_to eq error_400
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,10 +23,11 @@ RSpec.describe Gitlab::Pagination::Keyset::ColumnOrderDefinition do
|
|||
|
||||
let_it_be(:project_calculated_column_expression) do
|
||||
# COALESCE("projects"."description", 'No Description')
|
||||
Arel::Nodes::NamedFunction.new('COALESCE', [
|
||||
Project.arel_table[:description],
|
||||
Arel.sql("'No Description'")
|
||||
])
|
||||
Arel::Nodes::NamedFunction.new('COALESCE',
|
||||
[
|
||||
Project.arel_table[:description],
|
||||
Arel.sql("'No Description'")
|
||||
])
|
||||
end
|
||||
|
||||
let_it_be(:project_calculated_column) do
|
||||
|
|
|
|||
|
|
@ -117,23 +117,24 @@ RSpec.describe Gitlab::Pagination::Keyset::InOperatorOptimization::QueryBuilder
|
|||
let(:order) do
|
||||
# NULLS LAST ordering requires custom Order object for keyset pagination:
|
||||
# https://docs.gitlab.com/ee/development/database/keyset_pagination.html#complex-order-configuration
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :relative_position,
|
||||
column_expression: Issue.arel_table[:relative_position],
|
||||
order_expression: Issue.arel_table[:relative_position].desc.nulls_last,
|
||||
reversed_order_expression: Issue.arel_table[:relative_position].asc.nulls_first,
|
||||
order_direction: :desc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Issue.arel_table[:id].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :relative_position,
|
||||
column_expression: Issue.arel_table[:relative_position],
|
||||
order_expression: Issue.arel_table[:relative_position].desc.nulls_last,
|
||||
reversed_order_expression: Issue.arel_table[:relative_position].asc.nulls_first,
|
||||
order_direction: :desc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Issue.arel_table[:id].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:in_operator_optimization_options) do
|
||||
|
|
@ -279,17 +280,18 @@ RSpec.describe Gitlab::Pagination::Keyset::InOperatorOptimization::QueryBuilder
|
|||
context 'when ordering by SQL expression' do
|
||||
let(:order) do
|
||||
# ORDER BY (id * 10), id
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_multiplied_by_ten',
|
||||
order_expression: Arel.sql('(id * 10)').asc,
|
||||
sql_type: 'integer'
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Issue.arel_table[:id].asc
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_multiplied_by_ten',
|
||||
order_expression: Arel.sql('(id * 10)').asc,
|
||||
sql_type: 'integer'
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Issue.arel_table[:id].asc
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:scope) { Issue.reorder(order) }
|
||||
|
|
|
|||
|
|
@ -25,22 +25,24 @@ RSpec.describe Gitlab::Pagination::Keyset::InOperatorOptimization::Strategies::O
|
|||
|
||||
describe '#initializer_columns' do
|
||||
it 'returns NULLs for each ORDER BY columns' do
|
||||
expect(strategy.initializer_columns).to eq([
|
||||
'NULL::timestamp without time zone AS created_at',
|
||||
'NULL::integer AS id'
|
||||
])
|
||||
expect(strategy.initializer_columns).to eq(
|
||||
[
|
||||
'NULL::timestamp without time zone AS created_at',
|
||||
'NULL::integer AS id'
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an SQL expression is given' do
|
||||
context 'when the sql_type attribute is missing' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_times_ten',
|
||||
order_expression: Arel.sql('id * 10').asc
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_times_ten',
|
||||
order_expression: Arel.sql('id * 10').asc
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:keyset_scope) { Project.order(order) }
|
||||
|
|
@ -52,13 +54,14 @@ RSpec.describe Gitlab::Pagination::Keyset::InOperatorOptimization::Strategies::O
|
|||
|
||||
context 'when the sql_type_attribute is present' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_times_ten',
|
||||
order_expression: Arel.sql('id * 10').asc,
|
||||
sql_type: 'integer'
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id_times_ten',
|
||||
order_expression: Arel.sql('id * 10').asc,
|
||||
sql_type: 'integer'
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:keyset_scope) { Project.order(order) }
|
||||
|
|
|
|||
|
|
@ -15,21 +15,22 @@ RSpec.describe Gitlab::Pagination::Keyset::Iterator do
|
|||
let(:nulls_position) { :nulls_last }
|
||||
let(:reverse_nulls_position) { ::Gitlab::Pagination::Keyset::ColumnOrderDefinition::REVERSED_NULL_POSITIONS[nulls_position] }
|
||||
let(:custom_reorder) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: column,
|
||||
column_expression: klass.arel_table[column],
|
||||
order_expression: klass.arel_table[column].public_send(direction).public_send(nulls_position), # rubocop:disable GitlabSecurity/PublicSend
|
||||
reversed_order_expression: klass.arel_table[column].public_send(reverse_direction).public_send(reverse_nulls_position), # rubocop:disable GitlabSecurity/PublicSend
|
||||
order_direction: direction,
|
||||
nullable: nulls_position,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: klass.arel_table[:id].send(direction)
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: column,
|
||||
column_expression: klass.arel_table[column],
|
||||
order_expression: klass.arel_table[column].public_send(direction).public_send(nulls_position), # rubocop:disable GitlabSecurity/PublicSend
|
||||
reversed_order_expression: klass.arel_table[column].public_send(reverse_direction).public_send(reverse_nulls_position), # rubocop:disable GitlabSecurity/PublicSend
|
||||
order_direction: direction,
|
||||
nullable: nulls_position,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: klass.arel_table[:id].send(direction)
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:iterator_params) { nil }
|
||||
|
|
|
|||
|
|
@ -148,15 +148,16 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
end
|
||||
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
|
|
@ -192,29 +193,30 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
end
|
||||
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table['month'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table['month'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
|
|
@ -258,33 +260,34 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
end
|
||||
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table[:year].asc.nulls_last,
|
||||
reversed_order_expression: table[:year].desc.nulls_first,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table[:month].asc.nulls_last,
|
||||
reversed_order_expression: table[:month].desc.nulls_first,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table[:year].asc.nulls_last,
|
||||
reversed_order_expression: table[:year].desc.nulls_first,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table[:month].asc.nulls_last,
|
||||
reversed_order_expression: table[:month].desc.nulls_first,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_last,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
|
|
@ -324,33 +327,34 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
end
|
||||
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table[:year].asc.nulls_first,
|
||||
reversed_order_expression: table[:year].desc.nulls_last,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_first,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table[:month].asc.nulls_first,
|
||||
order_direction: :asc,
|
||||
reversed_order_expression: table[:month].desc.nulls_last,
|
||||
nullable: :nulls_first,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table[:year].asc.nulls_first,
|
||||
reversed_order_expression: table[:year].desc.nulls_last,
|
||||
order_direction: :asc,
|
||||
nullable: :nulls_first,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'month',
|
||||
column_expression: table['month'],
|
||||
order_expression: table[:month].asc.nulls_first,
|
||||
order_direction: :asc,
|
||||
reversed_order_expression: table[:month].desc.nulls_last,
|
||||
nullable: :nulls_first,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
|
|
@ -390,22 +394,23 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
end
|
||||
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:expected) do
|
||||
|
|
@ -432,33 +437,38 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
reversed = order.reversed_order
|
||||
before_conditions = reversed.where_values_with_or_query(before_cursor)
|
||||
|
||||
query = build_query(order: order, where_conditions: [Arel::Nodes::And.new([after_conditions, before_conditions])], limit: 100)
|
||||
query = build_query(
|
||||
order: order,
|
||||
where_conditions: [Arel::Nodes::And.new([after_conditions, before_conditions])],
|
||||
limit: 100)
|
||||
|
||||
expect(run_query(query)).to eq([
|
||||
{ "id" => 2, "year" => 2011, "month" => 0 },
|
||||
{ "id" => 6, "year" => 2012, "month" => 0 }
|
||||
])
|
||||
expect(run_query(query)).to eq(
|
||||
[
|
||||
{ "id" => 2, "year" => 2011, "month" => 0 },
|
||||
{ "id" => 6, "year" => 2012, "month" => 0 }
|
||||
])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ordering by the named function LOWER' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'title',
|
||||
column_expression: Arel::Nodes::NamedFunction.new("LOWER", [table['title'].desc]),
|
||||
order_expression: table['title'].lower.desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'title',
|
||||
column_expression: Arel::Nodes::NamedFunction.new("LOWER", [table['title'].desc]),
|
||||
order_expression: table['title'].lower.desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
let(:table_data) do
|
||||
|
|
@ -484,22 +494,23 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
|
||||
context 'when the passed cursor values do not match with the order definition' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'year',
|
||||
column_expression: table['year'],
|
||||
order_expression: table['year'].asc,
|
||||
nullable: :not_nullable,
|
||||
distinct: false
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
column_expression: table['id'],
|
||||
order_expression: table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
context 'when values are missing' do
|
||||
|
|
@ -553,14 +564,15 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
|
||||
context 'when string attribute name is given' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it_behaves_like 'cursor attribute examples'
|
||||
|
|
@ -568,14 +580,15 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
|
||||
context 'when symbol attribute name is given' do
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: :id,
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
it_behaves_like 'cursor attribute examples'
|
||||
|
|
@ -593,20 +606,21 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
|
||||
context 'when there are additional_projections' do
|
||||
let(:order) do
|
||||
order = Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'created_at_field',
|
||||
column_expression: Project.arel_table[:created_at],
|
||||
order_expression: Project.arel_table[:created_at].desc,
|
||||
order_direction: :desc,
|
||||
distinct: false,
|
||||
add_to_projections: true
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table[:id].desc
|
||||
)
|
||||
])
|
||||
order = Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'created_at_field',
|
||||
column_expression: Project.arel_table[:created_at],
|
||||
order_expression: Project.arel_table[:created_at].desc,
|
||||
order_direction: :desc,
|
||||
distinct: false,
|
||||
add_to_projections: true
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table[:id].desc
|
||||
)
|
||||
])
|
||||
|
||||
order
|
||||
end
|
||||
|
|
@ -684,20 +698,21 @@ RSpec.describe Gitlab::Pagination::Keyset::Order do
|
|||
describe '#attribute_names' do
|
||||
let(:expected_attribute_names) { %w(id name) }
|
||||
let(:order) do
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'name',
|
||||
order_expression: Project.arel_table['name'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'id',
|
||||
order_expression: Project.arel_table['id'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
),
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: 'name',
|
||||
order_expression: Project.arel_table['name'].desc,
|
||||
nullable: :not_nullable,
|
||||
distinct: true
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
subject { order.attribute_names }
|
||||
|
|
|
|||
|
|
@ -15,10 +15,11 @@ RSpec.describe Gitlab::ProjectTransfer do
|
|||
end
|
||||
|
||||
after do
|
||||
FileUtils.rm_rf([
|
||||
File.join(@root_dir, @namespace_path),
|
||||
File.join(@root_dir, @namespace_path_was)
|
||||
])
|
||||
FileUtils.rm_rf(
|
||||
[
|
||||
File.join(@root_dir, @namespace_path),
|
||||
File.join(@root_dir, @namespace_path_was)
|
||||
])
|
||||
end
|
||||
|
||||
describe '#move_project' do
|
||||
|
|
|
|||
|
|
@ -300,12 +300,13 @@ RSpec.describe Gitlab::PrometheusClient do
|
|||
it 'returns data from the API call' do
|
||||
req_stub = stub_prometheus_request(query_url, body: prometheus_values_body('matrix'))
|
||||
|
||||
expect(subject.query_range(prometheus_query)).to eq([
|
||||
{
|
||||
"metric" => {},
|
||||
"values" => [[1488758662.506, "0.00002996364761904785"], [1488758722.506, "0.00003090239047619091"]]
|
||||
}
|
||||
])
|
||||
expect(subject.query_range(prometheus_query)).to eq(
|
||||
[
|
||||
{
|
||||
"metric" => {},
|
||||
"values" => [[1488758662.506, "0.00002996364761904785"], [1488758722.506, "0.00003090239047619091"]]
|
||||
}
|
||||
])
|
||||
expect(req_stub).to have_been_requested
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,10 +52,11 @@ RSpec.describe Gitlab::PushOptions do
|
|||
end
|
||||
|
||||
it 'can parse multiple push options' do
|
||||
options = described_class.new([
|
||||
'merge_request.create',
|
||||
'merge_request.target=value'
|
||||
])
|
||||
options = described_class.new(
|
||||
[
|
||||
'merge_request.create',
|
||||
'merge_request.target=value'
|
||||
])
|
||||
|
||||
expect(options.get(:merge_request)).to include({
|
||||
create: true,
|
||||
|
|
@ -66,19 +67,21 @@ RSpec.describe Gitlab::PushOptions do
|
|||
end
|
||||
|
||||
it 'stores options internally as a HashWithIndifferentAccess' do
|
||||
options = described_class.new([
|
||||
'merge_request.create'
|
||||
])
|
||||
options = described_class.new(
|
||||
[
|
||||
'merge_request.create'
|
||||
])
|
||||
|
||||
expect(options.get('merge_request', 'create')).to eq(true)
|
||||
expect(options.get(:merge_request, :create)).to eq(true)
|
||||
end
|
||||
|
||||
it 'selects the last option when options contain duplicate namespace and key pairs' do
|
||||
options = described_class.new([
|
||||
'merge_request.target=value1',
|
||||
'merge_request.target=value2'
|
||||
])
|
||||
options = described_class.new(
|
||||
[
|
||||
'merge_request.target=value1',
|
||||
'merge_request.target=value2'
|
||||
])
|
||||
|
||||
expect(options.get(:merge_request, :target)).to eq('value2')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -217,10 +217,11 @@ RSpec.describe Gitlab::RackAttack::Request do
|
|||
subject { request.protected_path? }
|
||||
|
||||
before do
|
||||
stub_application_setting(protected_paths: [
|
||||
'/protected',
|
||||
'/secure'
|
||||
])
|
||||
stub_application_setting(
|
||||
protected_paths: [
|
||||
'/protected',
|
||||
'/secure'
|
||||
])
|
||||
end
|
||||
|
||||
where(:path, :expected) do
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@ RSpec.describe Gitlab::Search::AbuseDetection do
|
|||
|
||||
describe 'abusive character matching' do
|
||||
refs = %w(
|
||||
main
|
||||
тест
|
||||
maiñ
|
||||
main123
|
||||
main-v123
|
||||
main-v12.3
|
||||
feature/it_works
|
||||
really_important!
|
||||
测试
|
||||
)
|
||||
main
|
||||
тест
|
||||
maiñ
|
||||
main123
|
||||
main-v123
|
||||
main-v12.3
|
||||
feature/it_works
|
||||
really_important!
|
||||
测试
|
||||
)
|
||||
|
||||
refs.each do |ref|
|
||||
it "does match refs permitted by git refname: #{ref}" do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'getting job information' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:job) { create(:ci_build, :success, name: 'job1') }
|
||||
|
||||
let(:query) do
|
||||
graphql_query_for(:jobs)
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
let_it_be(:current_user) { create(:admin) }
|
||||
|
||||
it 'has full access to all jobs', :aggregate_failure do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(:jobs, :count)).to eq(1)
|
||||
expect(graphql_data_at(:jobs, :nodes)).to contain_exactly(a_graphql_entity_for(job))
|
||||
end
|
||||
|
||||
context 'when filtered by status' do
|
||||
let_it_be(:pending_job) { create(:ci_build, :pending) }
|
||||
let_it_be(:failed_job) { create(:ci_build, :failed) }
|
||||
|
||||
it 'gets pending jobs', :aggregate_failure do
|
||||
post_graphql(graphql_query_for(:jobs, { statuses: :PENDING }), current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(:jobs, :count)).to eq(1)
|
||||
expect(graphql_data_at(:jobs, :nodes)).to contain_exactly(a_graphql_entity_for(pending_job))
|
||||
end
|
||||
|
||||
it 'gets pending and failed jobs', :aggregate_failure do
|
||||
post_graphql(graphql_query_for(:jobs, { statuses: [:PENDING, :FAILED] }), current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(:jobs, :count)).to eq(2)
|
||||
expect(graphql_data_at(:jobs, :nodes)).to match_array([a_graphql_entity_for(pending_job),
|
||||
a_graphql_entity_for(failed_job)])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'if the user is not an admin' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
it 'has no access to the jobs', :aggregate_failure do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data_at(:jobs, :count)).to eq(0)
|
||||
expect(graphql_data_at(:jobs, :nodes)).to match_array([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -3,5 +3,107 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'getting merge access levels for a branch protection' do
|
||||
include_examples 'perform graphql requests for AccessLevel type objects', :merge
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:merge_access_level_data) { merge_access_levels_data[0] }
|
||||
|
||||
let(:merge_access_levels_data) do
|
||||
graphql_data_at('project',
|
||||
'branchRules',
|
||||
'nodes',
|
||||
0,
|
||||
'branchProtection',
|
||||
'mergeAccessLevels',
|
||||
'nodes')
|
||||
end
|
||||
|
||||
let(:project) { protected_branch.project }
|
||||
|
||||
let(:merge_access_levels_count) { protected_branch.merge_access_levels.size }
|
||||
|
||||
let(:variables) { { path: project.full_path } }
|
||||
|
||||
let(:fields) { all_graphql_fields_for('MergeAccessLevel') }
|
||||
|
||||
let(:query) do
|
||||
<<~GQL
|
||||
query($path: ID!) {
|
||||
project(fullPath: $path) {
|
||||
branchRules(first: 1) {
|
||||
nodes {
|
||||
branchProtection {
|
||||
mergeAccessLevels {
|
||||
nodes {
|
||||
#{fields}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GQL
|
||||
end
|
||||
|
||||
context 'when the user does not have read_protected_branch abilities' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch) }
|
||||
|
||||
before do
|
||||
project.add_guest(current_user)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it { expect(merge_access_levels_data).not_to be_present }
|
||||
end
|
||||
|
||||
shared_examples 'merge access request' do
|
||||
let(:merge_access) { protected_branch.merge_access_levels.first }
|
||||
|
||||
before do
|
||||
project.add_maintainer(current_user)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it 'returns all merge access levels' do
|
||||
expect(merge_access_levels_data.size).to eq(merge_access_levels_count)
|
||||
end
|
||||
|
||||
it 'includes access_level' do
|
||||
expect(merge_access_level_data['accessLevel'])
|
||||
.to eq(merge_access.access_level)
|
||||
end
|
||||
|
||||
it 'includes access_level_description' do
|
||||
expect(merge_access_level_data['accessLevelDescription'])
|
||||
.to eq(merge_access.humanize)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does have read_protected_branch abilities' do
|
||||
let(:merge_access) { protected_branch.merge_access_levels.first }
|
||||
|
||||
context 'when no one has access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_merge) }
|
||||
|
||||
it_behaves_like 'merge access request'
|
||||
end
|
||||
|
||||
context 'when developers have access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :developers_can_merge) }
|
||||
|
||||
it_behaves_like 'merge access request'
|
||||
end
|
||||
|
||||
context 'when maintainers have access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_merge) }
|
||||
|
||||
it_behaves_like 'merge access request'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,5 +3,107 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'getting push access levels for a branch protection' do
|
||||
include_examples 'perform graphql requests for AccessLevel type objects', :push
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:push_access_level_data) { push_access_levels_data[0] }
|
||||
|
||||
let(:push_access_levels_data) do
|
||||
graphql_data_at('project',
|
||||
'branchRules',
|
||||
'nodes',
|
||||
0,
|
||||
'branchProtection',
|
||||
'pushAccessLevels',
|
||||
'nodes')
|
||||
end
|
||||
|
||||
let(:project) { protected_branch.project }
|
||||
|
||||
let(:push_access_levels_count) { protected_branch.push_access_levels.size }
|
||||
|
||||
let(:variables) { { path: project.full_path } }
|
||||
|
||||
let(:fields) { all_graphql_fields_for('PushAccessLevel'.classify) }
|
||||
|
||||
let(:query) do
|
||||
<<~GQL
|
||||
query($path: ID!) {
|
||||
project(fullPath: $path) {
|
||||
branchRules(first: 1) {
|
||||
nodes {
|
||||
branchProtection {
|
||||
pushAccessLevels {
|
||||
nodes {
|
||||
#{fields}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GQL
|
||||
end
|
||||
|
||||
context 'when the user does not have read_protected_branch abilities' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch) }
|
||||
|
||||
before do
|
||||
project.add_guest(current_user)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it { expect(push_access_levels_data).not_to be_present }
|
||||
end
|
||||
|
||||
shared_examples 'push access request' do
|
||||
let(:push_access) { protected_branch.push_access_levels.first }
|
||||
|
||||
before do
|
||||
project.add_maintainer(current_user)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it 'returns all push access levels' do
|
||||
expect(push_access_levels_data.size).to eq(push_access_levels_count)
|
||||
end
|
||||
|
||||
it 'includes access_level' do
|
||||
expect(push_access_level_data['accessLevel'])
|
||||
.to eq(push_access.access_level)
|
||||
end
|
||||
|
||||
it 'includes access_level_description' do
|
||||
expect(push_access_level_data['accessLevelDescription'])
|
||||
.to eq(push_access.humanize)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does have read_protected_branch abilities' do
|
||||
let(:push_access) { protected_branch.push_access_levels.first }
|
||||
|
||||
context 'when no one has access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push) }
|
||||
|
||||
it_behaves_like 'push access request'
|
||||
end
|
||||
|
||||
context 'when developers have access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :developers_can_push) }
|
||||
|
||||
it_behaves_like 'push access request'
|
||||
end
|
||||
|
||||
context 'when maintainers have access' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_push) }
|
||||
|
||||
it_behaves_like 'push access request'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,24 +21,27 @@ RSpec.describe 'getting list of branch rules for a project' do
|
|||
|
||||
let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') }
|
||||
let(:variables) { { path: project.full_path } }
|
||||
let(:fields) { all_graphql_fields_for('BranchRule', max_depth: 2) }
|
||||
|
||||
let(:fields) do
|
||||
<<~QUERY
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
}
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
#{all_graphql_fields_for('branch_rules'.classify)}
|
||||
}
|
||||
}
|
||||
QUERY
|
||||
end
|
||||
|
||||
let(:query) do
|
||||
<<~GQL
|
||||
query($path: ID!, $n: Int, $cursor: String) {
|
||||
project(fullPath: $path) {
|
||||
branchRules(first: $n, after: $cursor) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
}
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
#{fields}
|
||||
}
|
||||
}
|
||||
}
|
||||
branchRules(first: $n, after: $cursor) { #{fields} }
|
||||
}
|
||||
}
|
||||
GQL
|
||||
|
|
@ -61,12 +64,15 @@ RSpec.describe 'getting list of branch rules for a project' do
|
|||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query' do
|
||||
it 'includes all fields', :aggregate_failures do
|
||||
expect(branch_rules_data.dig(0, 'node', 'name')).to be_present
|
||||
expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present
|
||||
expect(branch_rules_data.dig(0, 'node', 'updatedAt')).to be_present
|
||||
end
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it 'includes a name' do
|
||||
expect(branch_rules_data.dig(0, 'node', 'name')).to be_present
|
||||
end
|
||||
|
||||
it 'includes created_at and updated_at' do
|
||||
expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present
|
||||
expect(branch_rules_data.dig(1, 'node', 'updatedAt')).to be_present
|
||||
end
|
||||
|
||||
context 'when limiting the number of results' do
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'perform graphql requests for AccessLevel type objects' do |access_level_kind|
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:variables) { { path: project.full_path } }
|
||||
|
||||
let(:fields) { all_graphql_fields_for("#{access_level_kind.to_s.classify}AccessLevel", max_depth: 2) }
|
||||
let(:access_levels) { protected_branch.public_send("#{access_level_kind}_access_levels") }
|
||||
let(:access_levels_count) { access_levels.size }
|
||||
let(:maintainer_access_level) { access_levels.for_role.first }
|
||||
let(:user_access_level) { access_levels.for_user.first }
|
||||
let(:group_access_level) { access_levels.for_group.first }
|
||||
let(:user_access_level_data) { access_levels_data.find { |data| data['user'].present? } }
|
||||
let(:group_access_level_data) { access_levels_data.find { |data| data['group'].present? } }
|
||||
let(:maintainer_access_level_data) { access_levels_data.find { |data| data['user'].blank? && data['group'].blank? } }
|
||||
let(:access_levels_data) do
|
||||
graphql_data_at('project',
|
||||
'branchRules',
|
||||
'nodes',
|
||||
0,
|
||||
'branchProtection',
|
||||
"#{access_level_kind.to_s.camelize(:lower)}AccessLevels",
|
||||
'nodes')
|
||||
end
|
||||
|
||||
let(:query) do
|
||||
<<~GQL
|
||||
query($path: ID!) {
|
||||
project(fullPath: $path) {
|
||||
branchRules(first: 1) {
|
||||
nodes {
|
||||
branchProtection {
|
||||
#{access_level_kind.to_s.camelize(:lower)}AccessLevels {
|
||||
nodes {
|
||||
#{fields}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GQL
|
||||
end
|
||||
|
||||
describe 'requesting AccessLevel type objects as a guest user' do
|
||||
let_it_be(:protected_branch) { create(:protected_branch, project: project) }
|
||||
|
||||
before do
|
||||
create(:project_member, :guest, user: current_user, source: project)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it "does not return any #{access_level_kind.to_s.classify}AccessLevel objects" do
|
||||
expect(access_levels_data).not_to be_present
|
||||
end
|
||||
end
|
||||
|
||||
describe 'requesting AccessLevel type objects as a maintainer' do
|
||||
let_it_be(:protected_branch) do
|
||||
create(:protected_branch,
|
||||
"maintainers_can_#{access_level_kind}",
|
||||
"user_can_#{access_level_kind}",
|
||||
"group_can_#{access_level_kind}",
|
||||
project: project)
|
||||
end
|
||||
|
||||
before do
|
||||
create(:project_member, :maintainer, user: current_user, source: project)
|
||||
post_graphql(query, current_user: current_user, variables: variables)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query'
|
||||
|
||||
it "returns all #{access_level_kind} access level fields", :aggregate_failures do
|
||||
expect(access_levels_count).to eq(3),
|
||||
"Expected 3 #{access_level_kind.to_s.classify}AccessLevel records present, got #{access_levels_count}"
|
||||
expect(access_levels_data.size).to eq(access_levels_count)
|
||||
|
||||
[:maintainer, :user, :group].each do |access_level_type|
|
||||
access_level_data = public_send("#{access_level_type}_access_level_data")
|
||||
access_level = public_send("#{access_level_type}_access_level")
|
||||
|
||||
expect(access_level_data['accessLevel']).to eq(access_level.access_level)
|
||||
expect(access_level_data['accessLevelDescription']).to eq(access_level.humanize)
|
||||
|
||||
case access_level_type
|
||||
when :user
|
||||
expect(access_level_data.dig('user', 'name')).to eq(access_level.user.name)
|
||||
expect(access_level_data.dig('group', 'name')).to be_nil
|
||||
when :group
|
||||
expect(access_level_data.dig('group', 'name')).to eq(access_level.group.name)
|
||||
expect(access_level_data.dig('user', 'name')).to be_nil
|
||||
else
|
||||
expect(access_level_data.dig('group', 'name')).to be_nil
|
||||
expect(access_level_data.dig('user', 'name')).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -21,6 +21,6 @@ RSpec.describe 'shared/projects/_project.html.haml' do
|
|||
|
||||
render 'shared/projects/project', use_creator_avatar: true, project: project
|
||||
|
||||
expect(rendered).to have_selector('.project-avatar')
|
||||
expect(rendered).to have_selector('.gl-avatar-identicon')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -126,6 +126,19 @@ RSpec.describe Pages::InvalidateDomainCacheWorker do
|
|||
{ type: :namespace, id: 3 }
|
||||
]
|
||||
|
||||
it_behaves_like 'clears caches with',
|
||||
event_class: PagesDomains::PagesDomainDeletedEvent,
|
||||
event_data: {
|
||||
project_id: 1,
|
||||
namespace_id: 2,
|
||||
root_namespace_id: 3,
|
||||
domain: 'somedomain.com'
|
||||
},
|
||||
caches: [
|
||||
{ type: :project, id: 1 },
|
||||
{ type: :namespace, id: 3 }
|
||||
]
|
||||
|
||||
context 'when namespace based cache keys are duplicated' do
|
||||
# de-dups namespace cache keys
|
||||
it_behaves_like 'clears caches with',
|
||||
|
|
|
|||
Loading…
Reference in New Issue