From 19b2d736bf5bc1c6e348c3284b9aedd14536f874 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 14 Mar 2025 12:13:03 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rules.gitlab-ci.yml | 7 +- .rubocop.yml | 6 + .rubocop/internal_affairs.yml | 11 + .rubocop_todo/graphql/descriptions.yml | 17 -- ..._between_expect_offense_and_correction.yml | 6 + .../internal_affairs/example_description.yml | 11 + .../example_heredoc_delimiter.yml | 105 ++++++++ .../internal_affairs/location_expression.yml | 26 ++ .../internal_affairs/method_name_end_with.yml | 6 + .../internal_affairs/method_name_equal.yml | 15 ++ .../internal_affairs/node_destructuring.yml | 9 + .../node_first_or_last_argument.yml | 12 + .../node_matcher_directive.yml | 134 +++++++++++ .../internal_affairs/node_pattern_groups.yml | 6 + .../node_type_multiple_predicates.yml | 10 + .../internal_affairs/node_type_predicate.yml | 21 ++ .../internal_affairs/numblock_handler.yml | 14 ++ .../on_send_without_on_c_send.yml | 128 ++++++++++ .../processed_source_buffer_name.yml | 6 + .../redundant_expect_offense_arguments.yml | 7 + .../redundant_message_argument.yml | 20 ++ .../redundant_source_range.yml | 15 ++ .../useless_message_assertion.yml | 37 +++ .../javascripts/lib/utils/local_storage.js | 74 ++++++ .../javascripts/rapid_diffs/app/index.js | 2 + .../app/init_hidden_files_warning.js | 30 +++ .../rapid_diffs/stores/diffs_view.js | 5 + .../components/state_container.vue | 3 +- .../components/local_storage_sync.vue | 48 +--- .../work_items/pages/local_board.vue | 108 +++------ .../work_items/pages/object_pools.js | 175 ++++++++------ .../stylesheets/page_bundles/settings.scss | 3 + .../rapid_diffs/app_component.html.haml | 1 + app/finders/work_items/work_items_finder.rb | 5 + .../namespaces/work_items_resolver.rb | 4 +- .../types/namespace/package_settings_type.rb | 16 +- app/graphql/types/notes/noteable_interface.rb | 4 +- .../types/packages/cleanup/policy_type.rb | 2 +- .../types/packages/package_details_type.rb | 2 +- app/graphql/types/project_type.rb | 10 +- .../types/projects/branch_rule_type.rb | 8 +- app/graphql/types/release_links_type.rb | 10 +- app/graphql/types/repository/blob_type.rb | 8 +- app/graphql/types/snippet_type.rb | 4 +- .../types/terraform/state_version_type.rb | 4 +- app/graphql/types/todo_type.rb | 14 +- app/graphql/types/todoable_interface.rb | 4 +- app/graphql/types/user_interface.rb | 2 +- .../user_merge_request_interaction_type.rb | 10 +- app/models/active_session.rb | 12 +- app/models/repository.rb | 18 +- app/models/work_item.rb | 14 ++ app/views/projects/snippets/index.html.haml | 6 +- ...mary_and_secondary_stores_for_sessions.yml | 9 - ..._primary_store_as_default_for_sessions.yml | 9 - config/redis.yml.example | 18 +- ...3_ensure_id_uniqueness_for_p_ci_runners.rb | 19 ++ ..._id_uniqueness_for_p_ci_runner_machines.rb | 19 ++ db/schema_migrations/20250311113123 | 1 + db/schema_migrations/20250311113127 | 1 + db/structure.sql | 46 +++- doc/administration/raketasks/ldap.md | 168 ++++++++----- .../raketasks/uploads/migrate.md | 50 ++-- .../reference_architectures/25k_users.md | 2 +- .../reference_architectures/3k_users.md | 2 +- doc/api/graphql/reference/_index.md | 225 +++++++++--------- doc/ci/variables/predefined_variables.md | 15 +- doc/development/advanced_search.md | 12 +- .../cloud_connector/configuration.md | 1 + .../hardening_cicd_recommendations.md | 33 +-- .../templates/Jobs/SAST.latest.gitlab-ci.yml | 2 +- lib/gitlab/redis.rb | 1 - lib/gitlab/redis/cluster_sessions.rb | 14 -- lib/gitlab/redis/sessions.rb | 6 +- locale/gitlab.pot | 54 ++++- patches/vue-test-utils-compat+0.0.14.patch | 23 ++ .../merge_request/push_options_spec.rb | 8 +- rubocop/cop/.rubocop.yml | 3 + scripts/frontend/quarantined_vue3_specs.txt | 3 - scripts/undercoverage | 12 +- .../layouts/crud_component_preview.rb | 7 +- spec/db/schema_spec.rb | 6 +- .../work_items/work_items_finder_spec.rb | 71 ++++++ spec/frontend/lib/utils/local_storage_spec.js | 146 ++++++++++++ spec/frontend/rapid_diffs/app/app_spec.js | 3 + .../rapid_diffs/stores/diffs_view_spec.js | 9 + ...r_orphaned_project_runner_managers_spec.rb | 22 +- ...r_orphaned_project_runner_taggings_spec.rb | 16 +- .../lib/gitlab/redis/cluster_sessions_spec.rb | 7 - spec/lib/gitlab/redis/sessions_spec.rb | 6 - spec/rubocop/cop/.rubocop.yml | 3 + 91 files changed, 1664 insertions(+), 623 deletions(-) create mode 100644 .rubocop/internal_affairs.yml create mode 100644 .rubocop_todo/internal_affairs/empty_line_between_expect_offense_and_correction.yml create mode 100644 .rubocop_todo/internal_affairs/example_description.yml create mode 100644 .rubocop_todo/internal_affairs/example_heredoc_delimiter.yml create mode 100644 .rubocop_todo/internal_affairs/location_expression.yml create mode 100644 .rubocop_todo/internal_affairs/method_name_end_with.yml create mode 100644 .rubocop_todo/internal_affairs/method_name_equal.yml create mode 100644 .rubocop_todo/internal_affairs/node_destructuring.yml create mode 100644 .rubocop_todo/internal_affairs/node_first_or_last_argument.yml create mode 100644 .rubocop_todo/internal_affairs/node_matcher_directive.yml create mode 100644 .rubocop_todo/internal_affairs/node_pattern_groups.yml create mode 100644 .rubocop_todo/internal_affairs/node_type_multiple_predicates.yml create mode 100644 .rubocop_todo/internal_affairs/node_type_predicate.yml create mode 100644 .rubocop_todo/internal_affairs/numblock_handler.yml create mode 100644 .rubocop_todo/internal_affairs/on_send_without_on_c_send.yml create mode 100644 .rubocop_todo/internal_affairs/processed_source_buffer_name.yml create mode 100644 .rubocop_todo/internal_affairs/redundant_expect_offense_arguments.yml create mode 100644 .rubocop_todo/internal_affairs/redundant_message_argument.yml create mode 100644 .rubocop_todo/internal_affairs/redundant_source_range.yml create mode 100644 .rubocop_todo/internal_affairs/useless_message_assertion.yml create mode 100644 app/assets/javascripts/lib/utils/local_storage.js create mode 100644 app/assets/javascripts/rapid_diffs/app/init_hidden_files_warning.js delete mode 100644 config/feature_flags/gitlab_com_derisk/use_primary_and_secondary_stores_for_sessions.yml delete mode 100644 config/feature_flags/gitlab_com_derisk/use_primary_store_as_default_for_sessions.yml create mode 100644 db/post_migrate/20250311113123_ensure_id_uniqueness_for_p_ci_runners.rb create mode 100644 db/post_migrate/20250311113127_ensure_id_uniqueness_for_p_ci_runner_machines.rb create mode 100644 db/schema_migrations/20250311113123 create mode 100644 db/schema_migrations/20250311113127 delete mode 100644 lib/gitlab/redis/cluster_sessions.rb create mode 100644 patches/vue-test-utils-compat+0.0.14.patch create mode 100644 rubocop/cop/.rubocop.yml create mode 100644 spec/frontend/lib/utils/local_storage_spec.js delete mode 100644 spec/lib/gitlab/redis/cluster_sessions_spec.rb create mode 100644 spec/rubocop/cop/.rubocop.yml diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 395a2ce6531..615f314472e 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -698,6 +698,8 @@ .rubocop-patterns: &rubocop-patterns - ".{rubocop,rubocop_todo}.yml" + - "{,spec/}rubocop/cop/.rubocop.yml" + - ".rubocop/*.yml" - ".rubocop_todo/**/*.yml" - "{,ee/,jh/}rubocop/**/*" # We might be changing custom cops - "{,ee/,jh/}Gemfile.lock" # This should include gitlab-styles, rubocop itself, and any plugins we might be using @@ -3408,9 +3410,10 @@ ############################## .ai-gateway:rules:tagging: rules: - - if: '$AIGW_PIPELINE_TRIGGER_TOKEN == null' + - if: '$AIGW_TAGGING_ACCESS_TOKEN == null' when: never - - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+-ee$/' + - if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+(-ee)?$/' + # Only run when a version tag is created (release is cut) ################### # Benchmark rules # diff --git a/.rubocop.yml b/.rubocop.yml index 03421b0e190..14983e36b4c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,6 +5,8 @@ inherit_gem: require: - ./rubocop/rubocop - rubocop-rspec + # Always load these cop even if disabled by default so RuboCop knows about rules in TODOs. + - rubocop/cop/internal_affairs inherit_from: <% unless ENV['REVEAL_RUBOCOP_TODO'] == '1' %> @@ -74,6 +76,10 @@ Rails/Pluck: # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94047#note_1179689274 AutoCorrect: false +# Disabled by default and enabled via `.rubocop/internal_affairs.yml`. +InternalAffairs: + Enabled: false + RSpec: Language: Includes: diff --git a/.rubocop/internal_affairs.yml b/.rubocop/internal_affairs.yml new file mode 100644 index 00000000000..58cf98de909 --- /dev/null +++ b/.rubocop/internal_affairs.yml @@ -0,0 +1,11 @@ +--- +inherit_from: + - '../.rubocop.yml' + +InternalAffairs: + Enabled: true + +# This cop only checks for directives defined in `config/default.yml` +# whic does not apply here. +InternalAffairs/UndefinedConfig: + Enabled: false diff --git a/.rubocop_todo/graphql/descriptions.yml b/.rubocop_todo/graphql/descriptions.yml index 181c1d1a533..bafe298807c 100644 --- a/.rubocop_todo/graphql/descriptions.yml +++ b/.rubocop_todo/graphql/descriptions.yml @@ -2,23 +2,6 @@ # Cop supports --autocorrect. Graphql/Descriptions: Exclude: - - 'app/graphql/types/namespace/package_settings_type.rb' - - 'app/graphql/types/notes/noteable_interface.rb' - - 'app/graphql/types/packages/cleanup/policy_type.rb' - - 'app/graphql/types/packages/package_details_type.rb' - - 'app/graphql/types/project_type.rb' - - 'app/graphql/types/projects/branch_rule_type.rb' - - 'app/graphql/types/release_links_type.rb' - - 'app/graphql/types/repository/blob_type.rb' - - 'app/graphql/types/snippet_type.rb' - - 'app/graphql/types/terraform/state_version_type.rb' - - 'app/graphql/types/todo_type.rb' - - 'app/graphql/types/todoable_interface.rb' - - 'app/graphql/types/user_interface.rb' - - 'app/graphql/types/user_merge_request_interaction_type.rb' - - 'ee/app/graphql/ee/types/branch_protections/base_access_level_type.rb' - - 'ee/app/graphql/ee/types/branch_rules/branch_protection_type.rb' - - 'ee/app/graphql/ee/types/issue_type.rb' - 'ee/app/graphql/ee/types/projects/branch_rule_type.rb' - 'ee/app/graphql/ee/types/user_merge_request_interaction_type.rb' - 'ee/app/graphql/resolvers/epics_resolver.rb' diff --git a/.rubocop_todo/internal_affairs/empty_line_between_expect_offense_and_correction.yml b/.rubocop_todo/internal_affairs/empty_line_between_expect_offense_and_correction.yml new file mode 100644 index 00000000000..859a8125baf --- /dev/null +++ b/.rubocop_todo/internal_affairs/empty_line_between_expect_offense_and_correction.yml @@ -0,0 +1,6 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/EmptyLineBetweenExpectOffenseAndCorrection: + Details: grace period + Exclude: + - 'spec/rubocop/cop/rails/strong_params_spec.rb' diff --git a/.rubocop_todo/internal_affairs/example_description.yml b/.rubocop_todo/internal_affairs/example_description.yml new file mode 100644 index 00000000000..27ec3ea3938 --- /dev/null +++ b/.rubocop_todo/internal_affairs/example_description.yml @@ -0,0 +1,11 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/ExampleDescription: + Details: grace period + Exclude: + - 'spec/rubocop/cop/capybara/testid_finders_spec.rb' + - 'spec/rubocop/cop/database/avoid_using_pluck_without_limit_spec.rb' + - 'spec/rubocop/cop/database/disable_referential_integrity_spec.rb' + - 'spec/rubocop/cop/rails/migration_timestamp_spec.rb' + - 'spec/rubocop/cop/rake/require_spec.rb' + - 'spec/rubocop/cop/scalability/idempotent_worker_spec.rb' diff --git a/.rubocop_todo/internal_affairs/example_heredoc_delimiter.yml b/.rubocop_todo/internal_affairs/example_heredoc_delimiter.yml new file mode 100644 index 00000000000..db8d8f80b72 --- /dev/null +++ b/.rubocop_todo/internal_affairs/example_heredoc_delimiter.yml @@ -0,0 +1,105 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/ExampleHeredocDelimiter: + Details: grace period + Exclude: + - 'spec/rubocop/cop/active_model_errors_direct_manipulation_spec.rb' + - 'spec/rubocop/cop/active_record_association_reload_spec.rb' + - 'spec/rubocop/cop/api/base_spec.rb' + - 'spec/rubocop/cop/api/class_level_allow_access_with_scope_spec.rb' + - 'spec/rubocop/cop/api/ensure_string_detail_spec.rb' + - 'spec/rubocop/cop/api/grape_array_missing_coerce_spec.rb' + - 'spec/rubocop/cop/avoid_becomes_spec.rb' + - 'spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb' + - 'spec/rubocop/cop/ban_catch_throw_spec.rb' + - 'spec/rubocop/cop/capybara/testid_finders_spec.rb' + - 'spec/rubocop/cop/code_reuse/finder_spec.rb' + - 'spec/rubocop/cop/code_reuse/presenter_spec.rb' + - 'spec/rubocop/cop/code_reuse/serializer_spec.rb' + - 'spec/rubocop/cop/code_reuse/service_class_spec.rb' + - 'spec/rubocop/cop/code_reuse/worker_spec.rb' + - 'spec/rubocop/cop/database/disable_referential_integrity_spec.rb' + - 'spec/rubocop/cop/database/establish_connection_spec.rb' + - 'spec/rubocop/cop/database/multiple_databases_spec.rb' + - 'spec/rubocop/cop/database/rescue_query_canceled_spec.rb' + - 'spec/rubocop/cop/database/rescue_statement_timeout_spec.rb' + - 'spec/rubocop/cop/default_scope_spec.rb' + - 'spec/rubocop/cop/destroy_all_spec.rb' + - 'spec/rubocop/cop/feature_flag_usage_spec.rb' + - 'spec/rubocop/cop/file_decompression_spec.rb' + - 'spec/rubocop/cop/filename_length_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_current_organization_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_feature_category_not_owned_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_gitlab_instance_checks_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_uploaded_file_from_params_spec.rb' + - 'spec/rubocop/cop/gitlab/bounded_contexts_spec.rb' + - 'spec/rubocop/cop/gitlab/bulk_insert_spec.rb' + - 'spec/rubocop/cop/gitlab/change_timezone_spec.rb' + - 'spec/rubocop/cop/gitlab/const_get_inherit_false_spec.rb' + - 'spec/rubocop/cop/gitlab/delegate_predicate_methods_spec.rb' + - 'spec/rubocop/cop/gitlab/ee_only_class_spec.rb' + - 'spec/rubocop/cop/gitlab/event_store_subscriber_spec.rb' + - 'spec/rubocop/cop/gitlab/except_spec.rb' + - 'spec/rubocop/cop/gitlab/feature_available_usage_spec.rb' + - 'spec/rubocop/cop/gitlab/feature_flag_without_actor_spec.rb' + - 'spec/rubocop/cop/gitlab/finder_with_find_by_spec.rb' + - 'spec/rubocop/cop/gitlab/intersect_spec.rb' + - 'spec/rubocop/cop/gitlab/license_available_usage_spec.rb' + - 'spec/rubocop/cop/gitlab/namespaced_class_spec.rb' + - 'spec/rubocop/cop/gitlab/no_find_in_workers_spec.rb' + - 'spec/rubocop/cop/gitlab/policy_rule_boolean_spec.rb' + - 'spec/rubocop/cop/gitlab/predicate_memoization_spec.rb' + - 'spec/rubocop/cop/gitlab/rails_logger_spec.rb' + - 'spec/rubocop/cop/gitlab/service_response_spec.rb' + - 'spec/rubocop/cop/gitlab/token_without_prefix_spec.rb' + - 'spec/rubocop/cop/gitlab/union_spec.rb' + - 'spec/rubocop/cop/graphql/authorize_types_spec.rb' + - 'spec/rubocop/cop/graphql/descriptions_spec.rb' + - 'spec/rubocop/cop/graphql/enum_names_spec.rb' + - 'spec/rubocop/cop/graphql/enum_values_spec.rb' + - 'spec/rubocop/cop/graphql/graphql_name_position_spec.rb' + - 'spec/rubocop/cop/graphql/id_type_spec.rb' + - 'spec/rubocop/cop/graphql/resolver_type_spec.rb' + - 'spec/rubocop/cop/group_public_or_visible_to_user_spec.rb' + - 'spec/rubocop/cop/include_sidekiq_worker_spec.rb' + - 'spec/rubocop/cop/inject_enterprise_edition_module_spec.rb' + - 'spec/rubocop/cop/migration/add_index_spec.rb' + - 'spec/rubocop/cop/migration/background_migration_record_spec.rb' + - 'spec/rubocop/cop/migration/batch_migrations_post_only_spec.rb' + - 'spec/rubocop/cop/migration/drop_table_spec.rb' + - 'spec/rubocop/cop/migration/migration_record_spec.rb' + - 'spec/rubocop/cop/migration/migration_with_milestone_spec.rb' + - 'spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb' + - 'spec/rubocop/cop/performance/ar_count_each_spec.rb' + - 'spec/rubocop/cop/performance/ar_exists_and_present_blank_spec.rb' + - 'spec/rubocop/cop/performance/readlines_each_spec.rb' + - 'spec/rubocop/cop/project_path_helper_spec.rb' + - 'spec/rubocop/cop/put_group_routes_under_scope_spec.rb' + - 'spec/rubocop/cop/put_project_routes_under_scope_spec.rb' + - 'spec/rubocop/cop/rails/strong_params_spec.rb' + - 'spec/rubocop/cop/redis_queue_usage_spec.rb' + - 'spec/rubocop/cop/rspec/be_success_matcher_spec.rb' + - 'spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb' + - 'spec/rubocop/cop/rspec/env_assignment_spec.rb' + - 'spec/rubocop/cop/rspec/env_mocking_spec.rb' + - 'spec/rubocop/cop/rspec/expect_gitlab_tracking_spec.rb' + - 'spec/rubocop/cop/rspec/have_gitlab_http_status_spec.rb' + - 'spec/rubocop/cop/rspec/httparty_basic_auth_spec.rb' + - 'spec/rubocop/cop/rspec/modify_sidekiq_middleware_spec.rb' + - 'spec/rubocop/cop/rspec/top_level_describe_path_spec.rb' + - 'spec/rubocop/cop/safe_params_spec.rb' + - 'spec/rubocop/cop/scalability/bulk_perform_with_context_spec.rb' + - 'spec/rubocop/cop/scalability/cron_worker_context_spec.rb' + - 'spec/rubocop/cop/scalability/file_uploads_spec.rb' + - 'spec/rubocop/cop/scalability/idempotent_worker_spec.rb' + - 'spec/rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations_spec.rb' + - 'spec/rubocop/cop/search/namespaced_class_spec.rb' + - 'spec/rubocop/cop/sidekiq_api_usage_spec.rb' + - 'spec/rubocop/cop/sidekiq_load_balancing/worker_data_consistency_spec.rb' + - 'spec/rubocop/cop/sidekiq_options_queue_spec.rb' + - 'spec/rubocop/cop/sidekiq_redis_call_spec.rb' + - 'spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb' + - 'spec/rubocop/cop/usage_data/histogram_with_large_table_spec.rb' + - 'spec/rubocop/cop/usage_data/instrumentation_superclass_spec.rb' + - 'spec/rubocop/cop/usage_data/large_table_spec.rb' + - 'spec/rubocop/cop/user_admin_spec.rb' diff --git a/.rubocop_todo/internal_affairs/location_expression.yml b/.rubocop_todo/internal_affairs/location_expression.yml new file mode 100644 index 00000000000..b32267ffa11 --- /dev/null +++ b/.rubocop_todo/internal_affairs/location_expression.yml @@ -0,0 +1,26 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/LocationExpression: + Details: grace period + Exclude: + - 'rubocop/cop/avoid_route_redirect_leading_slash.rb' + - 'rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb' + - 'rubocop/cop/experiments_test_coverage.rb' + - 'rubocop/cop/gitlab/documentation_links/hardcoded_url.rb' + - 'rubocop/cop/gitlab/documentation_links/link.rb' + - 'rubocop/cop/gitlab/json.rb' + - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' + - 'rubocop/cop/gitlab/no_code_coverage_comment.rb' + - 'rubocop/cop/graphql/descriptions.rb' + - 'rubocop/cop/inject_enterprise_edition_module.rb' + - 'rubocop/cop/migration/update_column_in_batches.rb' + - 'rubocop/cop/performance/ar_count_each.rb' + - 'rubocop/cop/performance/ar_exists_and_present_blank.rb' + - 'rubocop/cop/performance/readlines_each.rb' + - 'rubocop/cop/rake/require.rb' + - 'rubocop/cop/rspec/any_instance_of.rb' + - 'rubocop/cop/rspec/be_success_matcher.rb' + - 'rubocop/cop/rspec/duplicate_spec_location.rb' + - 'rubocop/cop/rspec/env_assignment.rb' + - 'rubocop/cop/rspec/env_mocking.rb' + - 'rubocop/cop/rspec/modify_sidekiq_middleware.rb' diff --git a/.rubocop_todo/internal_affairs/method_name_end_with.yml b/.rubocop_todo/internal_affairs/method_name_end_with.yml new file mode 100644 index 00000000000..863cb28c70a --- /dev/null +++ b/.rubocop_todo/internal_affairs/method_name_end_with.yml @@ -0,0 +1,6 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/MethodNameEndWith: + Details: grace period + Exclude: + - 'rubocop/cop/gitlab/predicate_memoization.rb' diff --git a/.rubocop_todo/internal_affairs/method_name_equal.yml b/.rubocop_todo/internal_affairs/method_name_equal.yml new file mode 100644 index 00000000000..3def0e6fdf2 --- /dev/null +++ b/.rubocop_todo/internal_affairs/method_name_equal.yml @@ -0,0 +1,15 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/MethodNameEqual: + Details: grace period + Exclude: + - 'rubocop/cop/avoid_break_from_strong_memoize.rb' + - 'rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb' + - 'rubocop/cop/experiments_test_coverage.rb' + - 'rubocop/cop/gitlab/event_store_subscriber.rb' + - 'rubocop/cop/gitlab/finder_with_find_by.rb' + - 'rubocop/cop/gitlab/policy_rule_boolean.rb' + - 'rubocop/cop/migration/add_concurrent_index.rb' + - 'rubocop/cop/migration/remove_concurrent_index.rb' + - 'rubocop/cop/migration/with_lock_retries_disallowed_method.rb' + - 'rubocop/cop/migration/with_lock_retries_with_change.rb' diff --git a/.rubocop_todo/internal_affairs/node_destructuring.yml b/.rubocop_todo/internal_affairs/node_destructuring.yml new file mode 100644 index 00000000000..513b051793d --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_destructuring.yml @@ -0,0 +1,9 @@ +--- +InternalAffairs/NodeDestructuring: + Details: grace period + Exclude: + - 'rubocop/cop/ban_catch_throw.rb' + - 'rubocop/cop/gitlab/http_v2.rb' + - 'rubocop/cop/gitlab/httparty.rb' + - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' + - 'rubocop/cop/prefer_class_methods_over_module.rb' diff --git a/.rubocop_todo/internal_affairs/node_first_or_last_argument.yml b/.rubocop_todo/internal_affairs/node_first_or_last_argument.yml new file mode 100644 index 00000000000..fda4bc99d4e --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_first_or_last_argument.yml @@ -0,0 +1,12 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/NodeFirstOrLastArgument: + Details: grace period + Exclude: + - 'rubocop/cop/gitlab/const_get_inherit_false.rb' + - 'rubocop/cop/gitlab/documentation_links/link.rb' + - 'rubocop/cop/include_sidekiq_worker.rb' + - 'rubocop/cop/migration/change_column_null_on_high_traffic_table.rb' + - 'rubocop/cop/migration/versioned_migration_class.rb' + - 'rubocop/cop/scalability/cron_worker_context.rb' + - 'rubocop/cop/sidekiq_options_queue.rb' diff --git a/.rubocop_todo/internal_affairs/node_matcher_directive.yml b/.rubocop_todo/internal_affairs/node_matcher_directive.yml new file mode 100644 index 00000000000..16b7f4fa67c --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_matcher_directive.yml @@ -0,0 +1,134 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/NodeMatcherDirective: + Details: grace period + Exclude: + - 'rubocop/cop/active_model_errors_direct_manipulation.rb' + - 'rubocop/cop/active_record_association_reload.rb' + - 'rubocop/cop/api/base.rb' + - 'rubocop/cop/api/ensure_string_detail.rb' + - 'rubocop/cop/api/grape_array_missing_coerce.rb' + - 'rubocop/cop/avoid_becomes.rb' + - 'rubocop/cop/avoid_route_redirect_leading_slash.rb' + - 'rubocop/cop/background_migration/avoid_silent_rescue_exceptions.rb' + - 'rubocop/cop/background_migration/dictionary_file.rb' + - 'rubocop/cop/background_migration/feature_category.rb' + - 'rubocop/cop/capybara/testid_finders.rb' + - 'rubocop/cop/database/avoid_inheritance_column.rb' + - 'rubocop/cop/database/avoid_using_pluck_without_limit.rb' + - 'rubocop/cop/database/disable_referential_integrity.rb' + - 'rubocop/cop/database/establish_connection.rb' + - 'rubocop/cop/database/multiple_databases.rb' + - 'rubocop/cop/default_scope.rb' + - 'rubocop/cop/destroy_all.rb' + - 'rubocop/cop/feature_flag_usage.rb' + - 'rubocop/cop/file_decompression.rb' + - 'rubocop/cop/gemfile/missing_feature_category.rb' + - 'rubocop/cop/gemspec/avoid_executing_git.rb' + - 'rubocop/cop/gitlab/avoid_feature_category_not_owned.rb' + - 'rubocop/cop/gitlab/avoid_feature_get.rb' + - 'rubocop/cop/gitlab/avoid_uploaded_file_from_params.rb' + - 'rubocop/cop/gitlab/bulk_insert.rb' + - 'rubocop/cop/gitlab/change_timezone.rb' + - 'rubocop/cop/gitlab/const_get_inherit_false.rb' + - 'rubocop/cop/gitlab/delegate_predicate_methods.rb' + - 'rubocop/cop/gitlab/documentation_links/link.rb' + - 'rubocop/cop/gitlab/event_store_subscriber.rb' + - 'rubocop/cop/gitlab/except.rb' + - 'rubocop/cop/gitlab/feature_flag_without_actor.rb' + - 'rubocop/cop/gitlab/http_v2.rb' + - 'rubocop/cop/gitlab/httparty.rb' + - 'rubocop/cop/gitlab/intersect.rb' + - 'rubocop/cop/gitlab/json.rb' + - 'rubocop/cop/gitlab/keys_first_and_values_first.rb' + - 'rubocop/cop/gitlab/license_available_usage.rb' + - 'rubocop/cop/gitlab/no_find_in_workers.rb' + - 'rubocop/cop/gitlab/policy_rule_boolean.rb' + - 'rubocop/cop/gitlab/rails/safe_format.rb' + - 'rubocop/cop/gitlab/rails_logger.rb' + - 'rubocop/cop/gitlab/service_response.rb' + - 'rubocop/cop/gitlab/strong_memoize_attr.rb' + - 'rubocop/cop/gitlab/token_without_prefix.rb' + - 'rubocop/cop/gitlab/union.rb' + - 'rubocop/cop/graphql/authorize_types.rb' + - 'rubocop/cop/graphql/descriptions.rb' + - 'rubocop/cop/graphql/enum_names.rb' + - 'rubocop/cop/graphql/enum_values.rb' + - 'rubocop/cop/graphql/graphql_name_position.rb' + - 'rubocop/cop/graphql/id_type.rb' + - 'rubocop/cop/graphql/json_type.rb' + - 'rubocop/cop/graphql/old_types.rb' + - 'rubocop/cop/graphql/resolver_type.rb' + - 'rubocop/cop/graphql/resource_not_available_error.rb' + - 'rubocop/cop/group_public_or_visible_to_user.rb' + - 'rubocop/cop/ignored_columns.rb' + - 'rubocop/cop/include_sidekiq_worker.rb' + - 'rubocop/cop/migration/add_concurrent_foreign_key.rb' + - 'rubocop/cop/migration/add_limit_to_text_columns.rb' + - 'rubocop/cop/migration/background_migration_missing_active_concern.rb' + - 'rubocop/cop/migration/background_migration_record.rb' + - 'rubocop/cop/migration/batch_migrations_post_only.rb' + - 'rubocop/cop/migration/batched_migration_base_class.rb' + - 'rubocop/cop/migration/complex_indexes_require_name.rb' + - 'rubocop/cop/migration/create_table_with_foreign_keys.rb' + - 'rubocop/cop/migration/ensure_factory_for_table.rb' + - 'rubocop/cop/migration/migration_record.rb' + - 'rubocop/cop/migration/migration_with_milestone.rb' + - 'rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb' + - 'rubocop/cop/migration/prevent_index_creation.rb' + - 'rubocop/cop/migration/prevent_single_statement_with_disable_ddl_transaction.rb' + - 'rubocop/cop/migration/prevent_strings.rb' + - 'rubocop/cop/migration/refer_to_index_by_name.rb' + - 'rubocop/cop/migration/safer_boolean_column.rb' + - 'rubocop/cop/migration/schedule_async.rb' + - 'rubocop/cop/migration/schema_addition_methods_no_post.rb' + - 'rubocop/cop/migration/unfinished_dependencies.rb' + - 'rubocop/cop/migration/versioned_migration_class.rb' + - 'rubocop/cop/migration/with_lock_retries_disallowed_method.rb' + - 'rubocop/cop/performance/active_record_subtransactions.rb' + - 'rubocop/cop/performance/ar_count_each.rb' + - 'rubocop/cop/performance/ar_exists_and_present_blank.rb' + - 'rubocop/cop/performance/readlines_each.rb' + - 'rubocop/cop/prefer_class_methods_over_module.rb' + - 'rubocop/cop/put_group_routes_under_scope.rb' + - 'rubocop/cop/put_project_routes_under_scope.rb' + - 'rubocop/cop/qa/ambiguous_page_object_name.rb' + - 'rubocop/cop/qa/fabricate_usage.rb' + - 'rubocop/cop/qa/feature_flags.rb' + - 'rubocop/cop/rails/avoid_time_comparison.rb' + - 'rubocop/cop/rails/strong_params.rb' + - 'rubocop/cop/rake/require.rb' + - 'rubocop/cop/redis_queue_usage.rb' + - 'rubocop/cop/rspec/any_instance_of.rb' + - 'rubocop/cop/rspec/avoid_test_prof.rb' + - 'rubocop/cop/rspec/be_success_matcher.rb' + - 'rubocop/cop/rspec/before_all.rb' + - 'rubocop/cop/rspec/before_all_role_assignment.rb' + - 'rubocop/cop/rspec/env_assignment.rb' + - 'rubocop/cop/rspec/env_mocking.rb' + - 'rubocop/cop/rspec/expect_gitlab_tracking.rb' + - 'rubocop/cop/rspec/factories_in_migration_specs.rb' + - 'rubocop/cop/rspec/factory_bot/avoid_create.rb' + - 'rubocop/cop/rspec/factory_bot/inline_association.rb' + - 'rubocop/cop/rspec/factory_bot/local_static_assignment.rb' + - 'rubocop/cop/rspec/factory_bot/strategy_in_callback.rb' + - 'rubocop/cop/rspec/feature_category.rb' + - 'rubocop/cop/rspec/have_gitlab_http_status.rb' + - 'rubocop/cop/rspec/httparty_basic_auth.rb' + - 'rubocop/cop/rspec/modify_sidekiq_middleware.rb' + - 'rubocop/cop/rspec/web_mock_enable.rb' + - 'rubocop/cop/scalability/bulk_perform_with_context.rb' + - 'rubocop/cop/scalability/cron_worker_context.rb' + - 'rubocop/cop/scalability/file_uploads.rb' + - 'rubocop/cop/scalability/idempotent_worker.rb' + - 'rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb' + - 'rubocop/cop/sidekiq_api_usage.rb' + - 'rubocop/cop/sidekiq_load_balancing/worker_data_consistency.rb' + - 'rubocop/cop/sidekiq_options_queue.rb' + - 'rubocop/cop/sidekiq_redis_call.rb' + - 'rubocop/cop/static_translation_definition.rb' + - 'rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb' + - 'rubocop/cop/usage_data/histogram_with_large_table.rb' + - 'rubocop/cop/usage_data/instrumentation_superclass.rb' + - 'rubocop/cop/usage_data/large_table.rb' + - 'rubocop/cop/user_admin.rb' diff --git a/.rubocop_todo/internal_affairs/node_pattern_groups.yml b/.rubocop_todo/internal_affairs/node_pattern_groups.yml new file mode 100644 index 00000000000..1cf29057e8c --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_pattern_groups.yml @@ -0,0 +1,6 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/NodePatternGroups: + Details: grace period + Exclude: + - 'rubocop/cop/user_admin.rb' diff --git a/.rubocop_todo/internal_affairs/node_type_multiple_predicates.yml b/.rubocop_todo/internal_affairs/node_type_multiple_predicates.yml new file mode 100644 index 00000000000..59c64534dc9 --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_type_multiple_predicates.yml @@ -0,0 +1,10 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/NodeTypeMultiplePredicates: + Details: grace period + Exclude: + - 'rubocop/cop/gettext/static_identifier.rb' + - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' + - 'rubocop/cop/gitlab/rails/safe_format.rb' + - 'rubocop/cop/migration/add_reference.rb' + - 'rubocop/cop/search/namespaced_class.rb' diff --git a/.rubocop_todo/internal_affairs/node_type_predicate.yml b/.rubocop_todo/internal_affairs/node_type_predicate.yml new file mode 100644 index 00000000000..df2c4400f44 --- /dev/null +++ b/.rubocop_todo/internal_affairs/node_type_predicate.yml @@ -0,0 +1,21 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/NodeTypePredicate: + Details: grace period + Exclude: + - 'rubocop/cop/avoid_break_from_strong_memoize.rb' + - 'rubocop/cop/avoid_keyword_arguments_in_sidekiq_workers.rb' + - 'rubocop/cop/avoid_return_from_blocks.rb' + - 'rubocop/cop/graphql/descriptions.rb' + - 'rubocop/cop/migration/add_limit_to_text_columns.rb' + - 'rubocop/cop/migration/add_reference.rb' + - 'rubocop/cop/migration/background_migration_missing_active_concern.rb' + - 'rubocop/cop/migration/datetime.rb' + - 'rubocop/cop/migration/prevent_adding_columns.rb' + - 'rubocop/cop/migration/prevent_strings.rb' + - 'rubocop/cop/migration/refer_to_index_by_name.rb' + - 'rubocop/cop/prefer_class_methods_over_module.rb' + - 'rubocop/cop/project_path_helper.rb' + - 'rubocop/cop/rspec/have_gitlab_http_status.rb' + - 'rubocop/cop/static_translation_definition.rb' + - 'rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb' diff --git a/.rubocop_todo/internal_affairs/numblock_handler.yml b/.rubocop_todo/internal_affairs/numblock_handler.yml new file mode 100644 index 00000000000..39aceed84d9 --- /dev/null +++ b/.rubocop_todo/internal_affairs/numblock_handler.yml @@ -0,0 +1,14 @@ +--- +InternalAffairs/NumblockHandler: + Details: grace period + Exclude: + - 'rubocop/cop/avoid_break_from_strong_memoize.rb' + - 'rubocop/cop/avoid_return_from_blocks.rb' + - 'rubocop/cop/experiments_test_coverage.rb' + - 'rubocop/cop/gitlab/policy_rule_boolean.rb' + - 'rubocop/cop/gitlab/strong_memoize_attr.rb' + - 'rubocop/cop/migration/background_migration_missing_active_concern.rb' + - 'rubocop/cop/migration/with_lock_retries_disallowed_method.rb' + - 'rubocop/cop/qa/ambiguous_page_object_name.rb' + - 'rubocop/cop/rspec/feature_category.rb' + - 'rubocop/cop/rspec/shared_groups_metadata.rb' diff --git a/.rubocop_todo/internal_affairs/on_send_without_on_c_send.yml b/.rubocop_todo/internal_affairs/on_send_without_on_c_send.yml new file mode 100644 index 00000000000..3dcd7b4b9a4 --- /dev/null +++ b/.rubocop_todo/internal_affairs/on_send_without_on_c_send.yml @@ -0,0 +1,128 @@ +--- +InternalAffairs/OnSendWithoutOnCSend: + Details: grace period + Exclude: + - 'rubocop/cop/active_model_errors_direct_manipulation.rb' + - 'rubocop/cop/active_record_association_reload.rb' + - 'rubocop/cop/api/class_level_allow_access_with_scope.rb' + - 'rubocop/cop/api/ensure_string_detail.rb' + - 'rubocop/cop/api/grape_array_missing_coerce.rb' + - 'rubocop/cop/avoid_becomes.rb' + - 'rubocop/cop/avoid_route_redirect_leading_slash.rb' + - 'rubocop/cop/background_migration/feature_category.rb' + - 'rubocop/cop/ban_catch_throw.rb' + - 'rubocop/cop/capybara/testid_finders.rb' + - 'rubocop/cop/database/avoid_inheritance_column.rb' + - 'rubocop/cop/database/avoid_using_pluck_without_limit.rb' + - 'rubocop/cop/database/disable_referential_integrity.rb' + - 'rubocop/cop/database/establish_connection.rb' + - 'rubocop/cop/database/multiple_databases.rb' + - 'rubocop/cop/default_scope.rb' + - 'rubocop/cop/destroy_all.rb' + - 'rubocop/cop/feature_flag_usage.rb' + - 'rubocop/cop/file_decompression.rb' + - 'rubocop/cop/gemfile/missing_feature_category.rb' + - 'rubocop/cop/gettext/static_identifier.rb' + - 'rubocop/cop/gitlab/avoid_current_organization.rb' + - 'rubocop/cop/gitlab/avoid_feature_category_not_owned.rb' + - 'rubocop/cop/gitlab/avoid_feature_get.rb' + - 'rubocop/cop/gitlab/avoid_gitlab_instance_checks.rb' + - 'rubocop/cop/gitlab/avoid_uploaded_file_from_params.rb' + - 'rubocop/cop/gitlab/bulk_insert.rb' + - 'rubocop/cop/gitlab/change_timezone.rb' + - 'rubocop/cop/gitlab/const_get_inherit_false.rb' + - 'rubocop/cop/gitlab/delegate_predicate_methods.rb' + - 'rubocop/cop/gitlab/documentation_links/link.rb' + - 'rubocop/cop/gitlab/event_store_subscriber.rb' + - 'rubocop/cop/gitlab/except.rb' + - 'rubocop/cop/gitlab/feature_available_usage.rb' + - 'rubocop/cop/gitlab/feature_flag_without_actor.rb' + - 'rubocop/cop/gitlab/finder_with_find_by.rb' + - 'rubocop/cop/gitlab/http_v2.rb' + - 'rubocop/cop/gitlab/httparty.rb' + - 'rubocop/cop/gitlab/intersect.rb' + - 'rubocop/cop/gitlab/json.rb' + - 'rubocop/cop/gitlab/keys_first_and_values_first.rb' + - 'rubocop/cop/gitlab/license_available_usage.rb' + - 'rubocop/cop/gitlab/mark_used_feature_flags.rb' + - 'rubocop/cop/gitlab/no_find_in_workers.rb' + - 'rubocop/cop/gitlab/rails/safe_format.rb' + - 'rubocop/cop/gitlab/rails_logger.rb' + - 'rubocop/cop/gitlab/rspec/avoid_setup.rb' + - 'rubocop/cop/gitlab/service_response.rb' + - 'rubocop/cop/gitlab/token_without_prefix.rb' + - 'rubocop/cop/gitlab/union.rb' + - 'rubocop/cop/gitlab/without_reactive_cache.rb' + - 'rubocop/cop/graphql/descriptions.rb' + - 'rubocop/cop/graphql/enum_values.rb' + - 'rubocop/cop/graphql/id_type.rb' + - 'rubocop/cop/graphql/json_type.rb' + - 'rubocop/cop/graphql/old_types.rb' + - 'rubocop/cop/graphql/resource_not_available_error.rb' + - 'rubocop/cop/group_public_or_visible_to_user.rb' + - 'rubocop/cop/ignored_columns.rb' + - 'rubocop/cop/include_sidekiq_worker.rb' + - 'rubocop/cop/inject_enterprise_edition_module.rb' + - 'rubocop/cop/migration/add_concurrent_foreign_key.rb' + - 'rubocop/cop/migration/add_concurrent_index.rb' + - 'rubocop/cop/migration/add_timestamps.rb' + - 'rubocop/cop/migration/async_post_migrate_only.rb' + - 'rubocop/cop/migration/avoid_finalize_background_migration.rb' + - 'rubocop/cop/migration/background_migration_record.rb' + - 'rubocop/cop/migration/background_migrations.rb' + - 'rubocop/cop/migration/batch_migrations_post_only.rb' + - 'rubocop/cop/migration/change_column_null_on_high_traffic_table.rb' + - 'rubocop/cop/migration/create_table_with_foreign_keys.rb' + - 'rubocop/cop/migration/datetime.rb' + - 'rubocop/cop/migration/ensure_factory_for_table.rb' + - 'rubocop/cop/migration/prevent_adding_columns.rb' + - 'rubocop/cop/migration/remove_concurrent_index.rb' + - 'rubocop/cop/migration/safer_boolean_column.rb' + - 'rubocop/cop/migration/schedule_async.rb' + - 'rubocop/cop/migration/schema_addition_methods_no_post.rb' + - 'rubocop/cop/migration/update_column_in_batches.rb' + - 'rubocop/cop/migration/versioned_migration_class.rb' + - 'rubocop/cop/migration/with_lock_retries_with_change.rb' + - 'rubocop/cop/performance/active_record_subtransaction_methods.rb' + - 'rubocop/cop/performance/active_record_subtransactions.rb' + - 'rubocop/cop/performance/ar_count_each.rb' + - 'rubocop/cop/performance/ar_exists_and_present_blank.rb' + - 'rubocop/cop/performance/readlines_each.rb' + - 'rubocop/cop/project_path_helper.rb' + - 'rubocop/cop/qa/element_with_pattern.rb' + - 'rubocop/cop/qa/fabricate_usage.rb' + - 'rubocop/cop/qa/feature_flags.rb' + - 'rubocop/cop/rails/avoid_time_comparison.rb' + - 'rubocop/cop/rails/strong_params.rb' + - 'rubocop/cop/rake/require.rb' + - 'rubocop/cop/redis_queue_usage.rb' + - 'rubocop/cop/rspec/any_instance_of.rb' + - 'rubocop/cop/rspec/avoid_test_prof.rb' + - 'rubocop/cop/rspec/be_success_matcher.rb' + - 'rubocop/cop/rspec/before_all.rb' + - 'rubocop/cop/rspec/before_all_role_assignment.rb' + - 'rubocop/cop/rspec/env_assignment.rb' + - 'rubocop/cop/rspec/env_mocking.rb' + - 'rubocop/cop/rspec/expect_gitlab_tracking.rb' + - 'rubocop/cop/rspec/factories_in_migration_specs.rb' + - 'rubocop/cop/rspec/factory_bot/avoid_create.rb' + - 'rubocop/cop/rspec/factory_bot/inline_association.rb' + - 'rubocop/cop/rspec/factory_bot/local_static_assignment.rb' + - 'rubocop/cop/rspec/factory_bot/strategy_in_callback.rb' + - 'rubocop/cop/rspec/have_gitlab_http_status.rb' + - 'rubocop/cop/rspec/httparty_basic_auth.rb' + - 'rubocop/cop/rspec/modify_sidekiq_middleware.rb' + - 'rubocop/cop/rspec/web_mock_enable.rb' + - 'rubocop/cop/safe_params.rb' + - 'rubocop/cop/scalability/bulk_perform_with_context.rb' + - 'rubocop/cop/scalability/cron_worker_context.rb' + - 'rubocop/cop/scalability/file_uploads.rb' + - 'rubocop/cop/search/avoid_checking_finished_on_deprecated_migrations.rb' + - 'rubocop/cop/sidekiq_api_usage.rb' + - 'rubocop/cop/sidekiq_options_queue.rb' + - 'rubocop/cop/sidekiq_redis_call.rb' + - 'rubocop/cop/static_translation_definition.rb' + - 'rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb' + - 'rubocop/cop/usage_data/histogram_with_large_table.rb' + - 'rubocop/cop/usage_data/instrumentation_superclass.rb' + - 'rubocop/cop/usage_data/large_table.rb' diff --git a/.rubocop_todo/internal_affairs/processed_source_buffer_name.yml b/.rubocop_todo/internal_affairs/processed_source_buffer_name.yml new file mode 100644 index 00000000000..2e0b6080cc9 --- /dev/null +++ b/.rubocop_todo/internal_affairs/processed_source_buffer_name.yml @@ -0,0 +1,6 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/ProcessedSourceBufferName: + Details: grace period + Exclude: + - 'rubocop/cop/rspec/top_level_describe_path.rb' diff --git a/.rubocop_todo/internal_affairs/redundant_expect_offense_arguments.yml b/.rubocop_todo/internal_affairs/redundant_expect_offense_arguments.yml new file mode 100644 index 00000000000..da278c1b13d --- /dev/null +++ b/.rubocop_todo/internal_affairs/redundant_expect_offense_arguments.yml @@ -0,0 +1,7 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/RedundantExpectOffenseArguments: + Details: grace period + Exclude: + - 'spec/rubocop/cop/gitlab/namespaced_class_spec.rb' + - 'spec/rubocop/cop/search/namespaced_class_spec.rb' diff --git a/.rubocop_todo/internal_affairs/redundant_message_argument.yml b/.rubocop_todo/internal_affairs/redundant_message_argument.yml new file mode 100644 index 00000000000..626a7229ec6 --- /dev/null +++ b/.rubocop_todo/internal_affairs/redundant_message_argument.yml @@ -0,0 +1,20 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/RedundantMessageArgument: + Details: grace period + Exclude: + - 'rubocop/cop/feature_flag_usage.rb' + - 'rubocop/cop/file_decompression.rb' + - 'rubocop/cop/gitlab/feature_flag_without_actor.rb' + - 'rubocop/cop/gitlab/license_available_usage.rb' + - 'rubocop/cop/gitlab/no_find_in_workers.rb' + - 'rubocop/cop/migration/async_post_migrate_only.rb' + - 'rubocop/cop/migration/batch_migrations_post_only.rb' + - 'rubocop/cop/migration/migration_with_milestone.rb' + - 'rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction.rb' + - 'rubocop/cop/migration/prevent_single_statement_with_disable_ddl_transaction.rb' + - 'rubocop/cop/migration/schema_addition_methods_no_post.rb' + - 'rubocop/cop/redis_queue_usage.rb' + - 'rubocop/cop/rspec/shared_groups_metadata.rb' + - 'rubocop/cop/sidekiq_api_usage.rb' + - 'rubocop/cop/sidekiq_redis_call.rb' diff --git a/.rubocop_todo/internal_affairs/redundant_source_range.yml b/.rubocop_todo/internal_affairs/redundant_source_range.yml new file mode 100644 index 00000000000..14c0623fc30 --- /dev/null +++ b/.rubocop_todo/internal_affairs/redundant_source_range.yml @@ -0,0 +1,15 @@ +--- +# Cop supports --autocorrect. +InternalAffairs/RedundantSourceRange: + Details: grace period + Exclude: + - 'rubocop/cop/gitlab/const_get_inherit_false.rb' + - 'rubocop/cop/gitlab/documentation_links/link.rb' + - 'rubocop/cop/gitlab/http_v2.rb' + - 'rubocop/cop/gitlab/httparty.rb' + - 'rubocop/cop/gitlab/json.rb' + - 'rubocop/cop/inject_enterprise_edition_module.rb' + - 'rubocop/cop/project_path_helper.rb' + - 'rubocop/cop/rspec/before_all.rb' + - 'rubocop/cop/rspec/factory_bot/inline_association.rb' + - 'rubocop/cop/rspec/have_gitlab_http_status.rb' diff --git a/.rubocop_todo/internal_affairs/useless_message_assertion.yml b/.rubocop_todo/internal_affairs/useless_message_assertion.yml new file mode 100644 index 00000000000..43ef31a850a --- /dev/null +++ b/.rubocop_todo/internal_affairs/useless_message_assertion.yml @@ -0,0 +1,37 @@ +--- +InternalAffairs/UselessMessageAssertion: + Details: grace period + Exclude: + - 'spec/rubocop/cop/api/base_spec.rb' + - 'spec/rubocop/cop/api/class_level_allow_access_with_scope_spec.rb' + - 'spec/rubocop/cop/background_migration/avoid_silent_rescue_exceptions_spec.rb' + - 'spec/rubocop/cop/background_migration/dictionary_file_spec.rb' + - 'spec/rubocop/cop/background_migration/feature_category_spec.rb' + - 'spec/rubocop/cop/database/avoid_using_pluck_without_limit_spec.rb' + - 'spec/rubocop/cop/feature_flag_usage_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_feature_get_spec.rb' + - 'spec/rubocop/cop/gitlab/avoid_gitlab_instance_checks_spec.rb' + - 'spec/rubocop/cop/gitlab/feature_flag_without_actor_spec.rb' + - 'spec/rubocop/cop/gitlab/keys_first_and_values_first_spec.rb' + - 'spec/rubocop/cop/gitlab/license_available_usage_spec.rb' + - 'spec/rubocop/cop/gitlab/namespaced_class_spec.rb' + - 'spec/rubocop/cop/gitlab/no_code_coverage_comment_spec.rb' + - 'spec/rubocop/cop/gitlab/service_response_spec.rb' + - 'spec/rubocop/cop/gitlab/token_without_prefix_spec.rb' + - 'spec/rubocop/cop/graphql/enum_values_spec.rb' + - 'spec/rubocop/cop/migration/async_post_migrate_only_spec.rb' + - 'spec/rubocop/cop/migration/avoid_finalize_background_migration_spec.rb' + - 'spec/rubocop/cop/migration/batched_migration_base_class_spec.rb' + - 'spec/rubocop/cop/migration/migration_with_milestone_spec.rb' + - 'spec/rubocop/cop/migration/prevent_global_enable_lock_retries_with_disable_ddl_transaction_spec.rb' + - 'spec/rubocop/cop/migration/prevent_single_statement_with_disable_ddl_transaction_spec.rb' + - 'spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb' + - 'spec/rubocop/cop/performance/active_record_subtransaction_methods_spec.rb' + - 'spec/rubocop/cop/performance/active_record_subtransactions_spec.rb' + - 'spec/rubocop/cop/rake/require_spec.rb' + - 'spec/rubocop/cop/redis_queue_usage_spec.rb' + - 'spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb' + - 'spec/rubocop/cop/search/namespaced_class_spec.rb' + - 'spec/rubocop/cop/sidekiq_api_usage_spec.rb' + - 'spec/rubocop/cop/static_translation_definition_spec.rb' + - 'spec/rubocop/cop/user_admin_spec.rb' diff --git a/app/assets/javascripts/lib/utils/local_storage.js b/app/assets/javascripts/lib/utils/local_storage.js new file mode 100644 index 00000000000..00953f57ac7 --- /dev/null +++ b/app/assets/javascripts/lib/utils/local_storage.js @@ -0,0 +1,74 @@ +import { isString } from 'lodash'; + +/** + * Serializes a value for storage in localStorage + * @param {*} val - The value to serialize + * @param {boolean} asString - Whether to store as raw string (legacy mode) + * @returns {string} The serialized value + */ +const serializeValue = (val, asString = false) => { + if (!isString(val) && asString) { + // eslint-disable-next-line no-console + console.warn( + `[gitlab] LocalStorageSync is saving`, + val, + `but it is not a string and the 'asString' param is true. This will save and restore the stringified value rather than the original value.`, + ); + } + + return asString ? val : JSON.stringify(val); +}; + +/** + * Deserializes a value from localStorage + * @param {string} val - The stored string value + * @param {boolean} asString - Whether the value was stored as raw string (legacy mode) + * @returns {*} The deserialized value + */ +const deserializeValue = (val, asString = false) => { + return asString ? val : JSON.parse(val); +}; + +/** + * Gets a value from localStorage with proper deserialization + * @param {string} storageKey - The localStorage key + * @param {boolean} asString - Whether to treat as raw string (legacy mode) + * @returns {Object} Object with exists flag and value if it exists + */ +export const getStorageValue = (storageKey, asString = false) => { + const value = localStorage.getItem(storageKey); + + if (value === null) { + return { exists: false }; + } + + try { + return { exists: true, value: deserializeValue(value, asString) }; + } catch { + // eslint-disable-next-line no-console + console.warn( + `[gitlab] Failed to deserialize value from localStorage (key=${storageKey})`, + value, + ); + // default to "don't use localStorage value" + return { exists: false }; + } +}; + +/** + * Saves a value to localStorage with proper serialization + * @param {string} storageKey - The localStorage key + * @param {*} val - The value to store + * @param {boolean} asString - Whether to store as raw string (legacy mode) + */ +export const saveStorageValue = (storageKey, val, asString = false) => { + localStorage.setItem(storageKey, serializeValue(val, asString)); +}; + +/** + * Removes a value from localStorage + * @param {string} storageKey - The localStorage key to remove + */ +export const removeStorageValue = (storageKey) => { + localStorage.removeItem(storageKey); +}; diff --git a/app/assets/javascripts/rapid_diffs/app/index.js b/app/assets/javascripts/rapid_diffs/app/index.js index 81571e1e282..5a896ef7bc6 100644 --- a/app/assets/javascripts/rapid_diffs/app/index.js +++ b/app/assets/javascripts/rapid_diffs/app/index.js @@ -6,6 +6,7 @@ import { useDiffsList } from '~/rapid_diffs/stores/diffs_list'; import { initFileBrowser } from '~/rapid_diffs/app/init_file_browser'; import { StreamingError } from '~/rapid_diffs/streaming_error'; import { useDiffsView } from '~/rapid_diffs/stores/diffs_view'; +import { initHiddenFilesWarning } from '~/rapid_diffs/app/init_hidden_files_warning'; import { createAlert } from '~/alert'; import { __ } from '~/locale'; @@ -24,6 +25,7 @@ class RapidDiffsFacade { useDiffsView(pinia) .loadMetadata() .then(() => { + initHiddenFilesWarning(); initFileBrowser(); }) .catch(() => { diff --git a/app/assets/javascripts/rapid_diffs/app/init_hidden_files_warning.js b/app/assets/javascripts/rapid_diffs/app/init_hidden_files_warning.js new file mode 100644 index 00000000000..7fb995e3161 --- /dev/null +++ b/app/assets/javascripts/rapid_diffs/app/init_hidden_files_warning.js @@ -0,0 +1,30 @@ +import Vue from 'vue'; +import { mapState } from 'pinia'; +import { useDiffsView } from '~/rapid_diffs/stores/diffs_view'; +import { pinia } from '~/pinia/instance'; +import HiddenFilesWarning from '~/diffs/components/hidden_files_warning.vue'; + +export async function initHiddenFilesWarning() { + const el = document.querySelector('[data-hidden-files-warning]'); + + // eslint-disable-next-line no-new + new Vue({ + el, + pinia, + computed: { + ...mapState(useDiffsView, ['diffStats']), + }, + render(h) { + if (!this.diffStats?.renderOverflowWarning) return null; + + return h(HiddenFilesWarning, { + props: { + total: this.diffStats?.realSize, + visible: this.diffStats?.size, + plainDiffPath: this.diffStats?.plainDiffPath, + emailPatchPath: this.diffStats?.emailPatchPath, + }, + }); + }, + }); +} diff --git a/app/assets/javascripts/rapid_diffs/stores/diffs_view.js b/app/assets/javascripts/rapid_diffs/stores/diffs_view.js index 2773624d7e1..90a97fe4ab1 100644 --- a/app/assets/javascripts/rapid_diffs/stores/diffs_view.js +++ b/app/assets/javascripts/rapid_diffs/stores/diffs_view.js @@ -35,6 +35,11 @@ export const useDiffsView = defineStore('diffsView', { this.diffStats = { addedLines: store.state.diffs.addedLines, removedLines: store.state.diffs.removedLines, + size: store.state.diffs.size, + realSize: store.state.diffs.realSize, + plainDiffPath: store.state.diffs.plainDiffPath, + emailPatchPath: store.state.diffs.emailPatchPath, + renderOverflowWarning: store.state.diffs.renderOverflowWarning, // we will be using a number for that after refactoring diffsCount: parseInt(store.state.diffs.realSize, 10), }; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue index 61d283cab8f..50c1ddadecd 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/state_container.vue @@ -118,12 +118,13 @@ export default {
-import { isEqual, isString } from 'lodash'; +import { isEqual } from 'lodash'; +import { getStorageValue, saveStorageValue, removeStorageValue } from '~/lib/utils/local_storage'; /** * This component will save and restore a value to and from localStorage. @@ -44,61 +45,22 @@ export default { value(newVal) { if (!this.persist) return; - this.saveValue(this.serialize(newVal)); + saveStorageValue(this.storageKey, newVal, this.asString); }, clear(newVal) { if (newVal) { - localStorage.removeItem(this.storageKey); + removeStorageValue(this.storageKey); } }, }, mounted() { // On mount, trigger update if we actually have a localStorageValue - const { exists, value } = this.getStorageValue(); + const { exists, value } = getStorageValue(this.storageKey, this.asString); if (exists && !isEqual(value, this.value)) { this.$emit('input', value); } }, - methods: { - getStorageValue() { - const value = localStorage.getItem(this.storageKey); - - if (value === null) { - return { exists: false }; - } - - try { - return { exists: true, value: this.deserialize(value) }; - } catch { - // eslint-disable-next-line no-console - console.warn( - `[gitlab] Failed to deserialize value from localStorage (key=${this.storageKey})`, - value, - ); - // default to "don't use localStorage value" - return { exists: false }; - } - }, - saveValue(val) { - localStorage.setItem(this.storageKey, val); - }, - serialize(val) { - if (!isString(val) && this.asString) { - // eslint-disable-next-line no-console - console.warn( - `[gitlab] LocalStorageSync is saving`, - val, - `to the key "${this.storageKey}", but it is not a string and the 'asString' prop is true. This will save and restore the stringified value rather than the original value. If this is not intended, please remove or set the 'asString' prop to false.`, - ); - } - - return this.asString ? val : JSON.stringify(val); - }, - deserialize(val) { - return this.asString ? val : JSON.parse(val); - }, - }, render() { return this.$scopedSlots.default?.(); }, diff --git a/app/assets/javascripts/work_items/pages/local_board.vue b/app/assets/javascripts/work_items/pages/local_board.vue index 9a8c9353a9d..e48dc127484 100644 --- a/app/assets/javascripts/work_items/pages/local_board.vue +++ b/app/assets/javascripts/work_items/pages/local_board.vue @@ -1,12 +1,12 @@ @@ -112,19 +63,18 @@ export default {
- + - - - - +
- {{ hideEmpty ? __('Show empty') : __('Hide empty') }} + {{ hideEmpty ? s__('WorkItem|Show empty') : s__('WorkItem|Hide empty') }} - {{ __('Back') }} + {{ s__('WorkItem|Back') }}
@@ -133,7 +83,7 @@ export default {
  • - {{ __('No items') }} + {{ s__('WorkItem|No items') }}

  • diff --git a/app/assets/javascripts/work_items/pages/object_pools.js b/app/assets/javascripts/work_items/pages/object_pools.js index 6bc874e30e0..16dd435542a 100644 --- a/app/assets/javascripts/work_items/pages/object_pools.js +++ b/app/assets/javascripts/work_items/pages/object_pools.js @@ -1,4 +1,6 @@ -const getAssignees = (widgets) => { +import { s__ } from '~/locale'; + +export const getAssignees = (widgets) => { const found = widgets.find((widget) => widget.assignees !== undefined); if (found?.assignees) { return found.assignees?.nodes; @@ -6,7 +8,7 @@ const getAssignees = (widgets) => { return []; }; -const getLabels = (widgets) => { +export const getLabels = (widgets) => { const found = widgets.find((widget) => widget.labels !== undefined); if (found?.labels) { return found.labels?.nodes; @@ -14,7 +16,7 @@ const getLabels = (widgets) => { return []; }; -const getMilestone = (widgets) => { +export const getMilestone = (widgets) => { const found = widgets.find((widget) => widget.milestone !== undefined); if (found?.milestone) { return found.milestone; @@ -22,23 +24,7 @@ const getMilestone = (widgets) => { return undefined; }; -const getIteration = (widgets) => { - const found = widgets.find((widget) => widget.iteration !== undefined); - if (found?.iteration) { - return found.iteration; - } - return undefined; -}; - -const getHealthStatus = (widgets) => { - const found = widgets.find((widget) => widget.healthStatus !== undefined); - if (found?.healthStatus) { - return found.healthStatus; - } - return undefined; -}; - -const getReactions = (widgets) => { +export const getReactions = (widgets) => { const found = widgets.find((widget) => widget.awardEmoji !== undefined); if (found?.awardEmoji) { return found.awardEmoji.nodes; @@ -46,14 +32,6 @@ const getReactions = (widgets) => { return []; }; -const getWeight = (widgets) => { - const found = widgets.find((widget) => widget.weight !== undefined); - if (found?.weight) { - return { value: found.weight }; - } - return undefined; -}; - const transformItem = (input) => { return { id: input.id, @@ -65,71 +43,124 @@ const transformItem = (input) => { assignees: getAssignees(input.widgets), labels: getLabels(input.widgets), milestone: getMilestone(input.widgets), - iteration: getIteration(input.widgets), - healthStatus: getHealthStatus(input.widgets), webUrl: input.webUrl, confidential: input.confidential, reactions: getReactions(input.widgets), - weight: getWeight(input.widgets), }; }; -export const buildPools = (rawList) => { +export const buildPools = (rawList, transformer = transformItem) => { const pools = { - workItems: {}, - labels: {}, - users: {}, - milestones: {}, + workItems: new Map(), + labels: new Map(), + users: new Map(), + milestones: new Map(), }; - const flattened = rawList.map((raw) => transformItem(raw)); - for (const i of flattened) { + for (const raw of rawList) { + const i = transformer(raw); + const { labels, assignees, author, milestone } = i; - if (pools.workItems[i.id] === undefined) { - pools.workItems[i.id] = { - id: i.id, + const workItemId = i.id; + + // populate work item pool + if (!pools.workItems.has(workItemId)) { + pools.workItems.set(workItemId, { + id: workItemId, labels: labels.map((l) => l.id), author: author.id, assignees: assignees?.map((a) => a.id) || [], ...i, - }; + }); } + + // populate labels pool for (const label of labels) { - if (pools.labels[label.id]) { - pools.labels[label.id].workItems.push(i.id); - } else { - pools.labels[label.id] = { id: label.id, workItems: [i.id], ...label }; - } - } - if (pools.users[author.id]) { - pools.users[author.id].authored.push(i.id); - } else { - pools.users[author.id] = { id: author.id, authored: [i.id], assigned: [], ...author }; + const labelEntry = pools.labels.get(label.id) || { id: label.id, workItems: [], ...label }; + labelEntry.workItems.push(workItemId); + pools.labels.set(label.id, labelEntry); } + + // populate users pool with authors + const authorEntry = pools.users.get(author.id) || { + id: author.id, + authored: [], + assigned: [], + title: author.name, + ...author, + }; + authorEntry.authored.push(workItemId); + pools.users.set(author.id, authorEntry); + + // add assignees to users pool if (assignees) { for (const assignee of assignees) { - if (pools.users[assignee.id]) { - pools.users[assignee.id].assigned.push(i.id); - } else { - pools.users[assignee.id] = { - id: assignee.id, - authored: [], - assigned: [i.id], - ...assignee, - }; - } + const assigneeEntry = pools.users.get(assignee.id) || { + id: assignee.id, + authored: [], + assigned: [], + title: author.name, + ...assignee, + }; + assigneeEntry.assigned.push(workItemId); + pools.users.set(assignee.id, assigneeEntry); } } + + // populate milestones pool if (milestone) { - if (pools.milestones[milestone.id]) { - pools.milestones[milestone.id].workItems.push(i.id); - } else { - pools.milestones[milestone.id] = { - id: milestone.id, - workItems: [i.id], - ...milestone, - }; - } + const milestoneEntry = pools.milestones.get(milestone.id) || { + id: milestone.id, + workItems: [], + ...milestone, + }; + milestoneEntry.workItems.push(workItemId); + pools.milestones.set(milestone.id, milestoneEntry); } } - return pools; + + return { + workItems: Object.fromEntries(pools.workItems), + labels: Object.fromEntries(pools.labels), + users: Object.fromEntries(pools.users), + milestones: Object.fromEntries(pools.milestones), + }; +}; + +export const getGroupOptions = () => { + return [ + { value: 'label', label: s__('WorkItem|Label') }, + { value: 'assignee', label: s__('WorkItem|Assignee') }, + { value: 'author', label: s__('WorkItem|Author') }, + { value: 'milestone', label: s__('WorkItem|Milestone') }, + ]; +}; + +export const getPoolNameForGrouping = (groupingName) => { + return { + label: 'labels', + assignee: 'users', + author: 'users', + milestone: 'milestones', + }[groupingName]; +}; + +function subtractArrays(arr1, arr2) { + const setB = new Set(arr2); + return arr1.filter((item) => !setB.has(item)); +} + +export const groupBy = ({ pool, itemIds, hideEmpty, noneLabel, itemsProperty = 'workItems' }) => { + const groups = []; + const includedItemIds = []; + for (const i of Object.values(pool)) { + groups.push({ + title: i.title, + items: i[itemsProperty], + }); + includedItemIds.push(...i[itemsProperty]); + } + const notIncluded = subtractArrays(itemIds, includedItemIds); + return [{ title: noneLabel, items: notIncluded }, ...groups].filter((g) => + hideEmpty ? g.items.length > 0 : true, + ); }; diff --git a/app/assets/stylesheets/page_bundles/settings.scss b/app/assets/stylesheets/page_bundles/settings.scss index f634f630d1d..7eb11566e81 100644 --- a/app/assets/stylesheets/page_bundles/settings.scss +++ b/app/assets/stylesheets/page_bundles/settings.scss @@ -44,6 +44,7 @@ } .settings-toggle svg { + @include gl-prefers-reduced-motion-transition; @apply gl-transition; } @@ -90,6 +91,7 @@ } .settings-content { + @include gl-prefers-reduced-motion-animation; // #416312: Fix white space at bottom of page position: relative; max-height: 1px; @@ -101,6 +103,7 @@ margin-bottom: $gl-spacing-scale-5; .settings.expanded & { + @include gl-prefers-reduced-motion-animation; max-height: none; overflow-y: visible; animation: expandMaxHeight 300ms ease-in; diff --git a/app/components/rapid_diffs/app_component.html.haml b/app/components/rapid_diffs/app_component.html.haml index 417e49f64f2..22c4808375b 100644 --- a/app/components/rapid_diffs/app_component.html.haml +++ b/app/components/rapid_diffs/app_component.html.haml @@ -7,6 +7,7 @@ .rd-app-sidebar-loading = helpers.gl_loading_icon(size: 'sm') .rd-app-content{ data: { sidebar_visible: true } } + .rd-app-content-header{ data: { hidden_files_warning: true } } .code{ class: helpers.user_color_scheme } %div{ data: { diffs_list: true } } = javascript_tag nonce: content_security_policy_nonce do diff --git a/app/finders/work_items/work_items_finder.rb b/app/finders/work_items/work_items_finder.rb index 64376368fe5..36a6d6e4308 100644 --- a/app/finders/work_items/work_items_finder.rb +++ b/app/finders/work_items/work_items_finder.rb @@ -7,6 +7,7 @@ module WorkItems class WorkItemsFinder < IssuesFinder include Gitlab::Utils::StrongMemoize + include TimeFrameFilter def klass WorkItem @@ -21,6 +22,10 @@ module WorkItems def filter_items(items) items = super(items) + # We require namespace_level_work_items to be true here, since we need the namespace_ids CTE provided by the + # by_parent method for performance reasons see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181904 + items = by_timeframe(items) if include_namespace_level_work_items? + by_widgets(items) end diff --git a/app/graphql/resolvers/namespaces/work_items_resolver.rb b/app/graphql/resolvers/namespaces/work_items_resolver.rb index d9b199d3398..cbaa1c991d2 100644 --- a/app/graphql/resolvers/namespaces/work_items_resolver.rb +++ b/app/graphql/resolvers/namespaces/work_items_resolver.rb @@ -4,6 +4,8 @@ module Resolvers module Namespaces # rubocop:disable Graphql/ResolverType -- inherited from Resolvers::WorkItemsResolver class WorkItemsResolver < ::Resolvers::WorkItemsResolver + include TimeFrameArguments + argument :include_ancestors, GraphQL::Types::Boolean, required: false, default_value: false, @@ -30,7 +32,7 @@ module Resolvers def finder(args) ::WorkItems::WorkItemsFinder.new( current_user, - args.merge(group_id: resource_parent) + args.merge(group_id: resource_parent, **transform_timeframe_parameters(args)) ) end end diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb index 45730b0e072..d2e6abeeaf0 100644 --- a/app/graphql/types/namespace/package_settings_type.rb +++ b/app/graphql/types/namespace/package_settings_type.rb @@ -14,37 +14,37 @@ module Types 'match this regex. Otherwise, this setting has no effect.' field :generic_duplicates_allowed, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether duplicate generic packages are allowed for this namespace.' + description: 'Indicates whether duplicate generic packages are allowed for the namespace.' field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that ' \ 'match this regex. Otherwise, this setting has no effect.' field :maven_duplicates_allowed, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' + description: 'Indicates whether duplicate Maven packages are allowed for the namespace.' field :maven_package_requests_forwarding, GraphQL::Types::Boolean, null: true, - description: 'Indicates whether Maven package forwarding is allowed for this namespace.' + description: 'Indicates whether Maven package forwarding is allowed for the namespace.' field :npm_package_requests_forwarding, GraphQL::Types::Boolean, null: true, - description: 'Indicates whether npm package forwarding is allowed for this namespace.' + description: 'Indicates whether npm package forwarding is allowed for the namespace.' field :nuget_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When nuget_duplicates_allowed is false, you can publish duplicate packages with names that ' \ 'match this regex. Otherwise, this setting has no effect. ' field :nuget_duplicates_allowed, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether duplicate NuGet packages are allowed for this namespace.' + description: 'Indicates whether duplicate NuGet packages are allowed for the namespace.' field :pypi_package_requests_forwarding, GraphQL::Types::Boolean, null: true, - description: 'Indicates whether PyPI package forwarding is allowed for this namespace.' + description: 'Indicates whether PyPI package forwarding is allowed for the namespace.' field :terraform_module_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When terraform_module_duplicates_allowed is false, you can publish duplicate packages with ' \ 'names that match this regex. Otherwise, this setting has no effect.' field :terraform_module_duplicates_allowed, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether duplicate Terraform packages are allowed for this namespace.' + description: 'Indicates whether duplicate Terraform packages are allowed for the namespace.' field :lock_maven_package_requests_forwarding, GraphQL::Types::Boolean, null: false, @@ -71,7 +71,7 @@ module Types field :nuget_symbol_server_enabled, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether the NuGet symbol server is enabled for this namespace.' + description: 'Indicates whether the NuGet symbol server is enabled for the namespace.' end end diff --git a/app/graphql/types/notes/noteable_interface.rb b/app/graphql/types/notes/noteable_interface.rb index e04da811b38..15580f63d09 100644 --- a/app/graphql/types/notes/noteable_interface.rb +++ b/app/graphql/types/notes/noteable_interface.rb @@ -8,8 +8,8 @@ module Types field :notes, resolver: Resolvers::Noteable::NotesResolver, null: false, description: "All notes on this noteable." field :discussions, Types::Notes::DiscussionType.connection_type, null: false, - description: "All discussions on this noteable." - field :commenters, Types::UserType.connection_type, null: false, description: "All commenters on this noteable." + description: "All discussions on the noteable." + field :commenters, Types::UserType.connection_type, null: false, description: "All commenters on the noteable." def self.resolve_type(object, context) case object diff --git a/app/graphql/types/packages/cleanup/policy_type.rb b/app/graphql/types/packages/cleanup/policy_type.rb index a602d84cc54..f1b79e969e4 100644 --- a/app/graphql/types/packages/cleanup/policy_type.rb +++ b/app/graphql/types/packages/cleanup/policy_type.rb @@ -16,7 +16,7 @@ module Types field :next_run_at, Types::TimeType, null: true, - description: 'Next time that this packages cleanup policy will be executed.' + description: 'Next time that the packages cleanup policy will be executed.' end end end diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index a90b39b8f00..629e3fbacc2 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -33,7 +33,7 @@ module Types field :pypi_url, GraphQL::Types::String, null: true, description: 'Url of the PyPi project endpoint.' field :last_downloaded_at, Types::TimeType, null: true, - description: 'Last time that a file of this package was downloaded.' + description: 'Last time that a file of the package was downloaded.' field :public_package, GraphQL::Types::Boolean, null: true, description: 'Indicates if there is public access to the package.' diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index e1d560ff705..73ec5b73a31 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -143,7 +143,7 @@ module Types field :max_access_level, Types::AccessLevelType, null: false, - description: 'The maximum access level of the current user in the project.' + description: 'Maximum access level of the current user in the project.' field :merge_requests_ff_only_enabled, GraphQL::Types::Boolean, null: true, @@ -568,7 +568,7 @@ module Types field :label, Types::LabelType, null: true, - description: 'Label available on this project.' do + description: 'Label available on the project.' do argument :title, GraphQL::Types::String, required: true, description: 'Title of the label.' @@ -682,7 +682,7 @@ module Types field :forked_from, Types::ProjectType, null: true, - description: 'Project this project was forked from.', + description: 'Project the project was forked from.', method: :forked_from_project field :branch_rules, Types::Projects::BranchRuleType.connection_type, @@ -777,7 +777,7 @@ module Types field :protectable_branches, [GraphQL::Types::String], - description: 'List of unprotected branches, ignoring any wildcard branch rules', + description: 'List of unprotected branches, ignoring any wildcard branch rules.', null: true, calls_gitaly: true, experiment: { milestone: '16.9' }, @@ -797,7 +797,7 @@ module Types authorize: :admin_project do argument :title_query, GraphQL::Types::String, required: false, - description: 'Term by which to search deploy key titles' + description: 'Term by which to search deploy key titles.' end field :pages_deployments, Types::PagesDeploymentType.connection_type, null: true, diff --git a/app/graphql/types/projects/branch_rule_type.rb b/app/graphql/types/projects/branch_rule_type.rb index aa54b71ee7c..cf97472d9fd 100644 --- a/app/graphql/types/projects/branch_rule_type.rb +++ b/app/graphql/types/projects/branch_rule_type.rb @@ -22,24 +22,24 @@ module Types null: false, method: :default_branch?, calls_gitaly: true, - description: "Check if this branch rule protects the project's default branch." + description: "Check if the branch rule protects the project's default branch." field :is_protected, type: GraphQL::Types::Boolean, null: false, method: :protected?, - description: "Check if this branch rule protects access for the branch." + description: "Check if the branch rule protects access for the branch." field :matching_branches_count, type: GraphQL::Types::Int, null: false, calls_gitaly: true, - description: 'Number of existing branches that match this branch rule.' + description: 'Number of existing branches that match the branch rule.' field :branch_protection, type: Types::BranchRules::BranchProtectionType, null: true, - description: 'Branch protections configured for this branch rule.' + description: 'Branch protections configured for the branch rule.' field :created_at, Types::TimeType, diff --git a/app/graphql/types/release_links_type.rb b/app/graphql/types/release_links_type.rb index 43001ec5604..1dced7b2174 100644 --- a/app/graphql/types/release_links_type.rb +++ b/app/graphql/types/release_links_type.rb @@ -13,12 +13,12 @@ module Types field :closed_issues_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the issues page, filtered by this release and `state=closed`.', + description: 'HTTP URL of the issues page, filtered by the release and `state=closed`.', authorize: :read_code field :closed_merge_requests_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the merge request page , filtered by this release and `state=closed`.', + description: 'HTTP URL of the merge request page, filtered by the release and `state=closed`.', authorize: :read_code field :edit_url, GraphQL::Types::String, null: true, description: "HTTP URL of the release's edit page.", @@ -26,17 +26,17 @@ module Types field :merged_merge_requests_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the merge request page , filtered by this release and `state=merged`.', + description: 'HTTP URL of the merge request page, filtered by the release and `state=merged`.', authorize: :read_code field :opened_issues_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the issues page, filtered by this release and `state=open`.', + description: 'HTTP URL of the issues page, filtered by the release and `state=open`.', authorize: :read_code field :opened_merge_requests_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the merge request page, filtered by this release and `state=open`.', + description: 'HTTP URL of the merge request page, filtered by the release and `state=open`.', authorize: :read_code field :self_url, GraphQL::Types::String, null: true, description: 'HTTP URL of the release.' diff --git a/app/graphql/types/repository/blob_type.rb b/app/graphql/types/repository/blob_type.rb index ba3608cafa5..15bed4d40d4 100644 --- a/app/graphql/types/repository/blob_type.rb +++ b/app/graphql/types/repository/blob_type.rb @@ -33,16 +33,16 @@ module Types description: 'Web path of the blob.' field :ide_edit_path, GraphQL::Types::String, null: true, - description: 'Web path to edit this blob in the Web IDE.' + description: 'Web path to edit the blob in the Web IDE.' field :fork_and_edit_path, GraphQL::Types::String, null: true, - description: 'Web path to edit this blob using a forked project.' + description: 'Web path to edit the blob using a forked project.' field :ide_fork_and_edit_path, GraphQL::Types::String, null: true, - description: 'Web path to edit this blob in the Web IDE using a forked project.' + description: 'Web path to edit the blob in the Web IDE using a forked project.' field :fork_and_view_path, GraphQL::Types::String, null: true, - description: 'Web path to view this blob using a forked project.' + description: 'Web path to view the blob using a forked project.' field :size, GraphQL::Types::BigInt, null: true, description: 'Size (in bytes) of the blob.' diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index 3725ace36c6..bed8ab5d65e 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -51,11 +51,11 @@ module Types method: :hidden_due_to_author_ban? field :created_at, Types::TimeType, - description: 'Timestamp this snippet was created.', + description: 'Timestamp the snippet was created.', null: false field :updated_at, Types::TimeType, - description: 'Timestamp this snippet was updated.', + description: 'Timestamp the snippet was updated.', null: false field :web_url, type: GraphQL::Types::String, diff --git a/app/graphql/types/terraform/state_version_type.rb b/app/graphql/types/terraform/state_version_type.rb index 64e9363eead..cd19fea75e7 100644 --- a/app/graphql/types/terraform/state_version_type.rb +++ b/app/graphql/types/terraform/state_version_type.rb @@ -15,7 +15,7 @@ module Types field :created_by_user, Types::UserType, null: true, - description: 'User that created this version.' + description: 'User that created the version.' field :download_path, GraphQL::Types::String, null: true, @@ -23,7 +23,7 @@ module Types field :job, Types::Ci::JobType, null: true, - description: 'Job that created this version.', + description: 'Job that created the version.', authorize: :read_commit_status field :serial, GraphQL::Types::Int, diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb index 6e765fa7674..4f53d01bf77 100644 --- a/app/graphql/types/todo_type.rb +++ b/app/graphql/types/todo_type.rb @@ -16,15 +16,15 @@ module Types null: false field :project, Types::ProjectType, - description: 'Project this to-do item is associated with.', + description: 'Project the to-do item is associated with.', null: true field :group, 'Types::GroupType', - description: 'Group this to-do item is associated with.', + description: 'Group the to-do item is associated with.', null: true field :author, Types::UserType, - description: 'Author of this to-do item.', + description: 'Author of the to-do item.', null: false field :action, Types::TodoActionEnum, @@ -38,7 +38,7 @@ module Types null: false field :target_entity, Types::TodoableInterface, - description: 'Target of the to-do item', + description: 'Target of the to-do item.', calls_gitaly: true, null: true @@ -60,11 +60,11 @@ module Types null: false field :created_at, Types::TimeType, - description: 'Timestamp this to-do item was created.', + description: 'Timestamp the to-do item was created.', null: false field :note, Types::Notes::NoteType, - description: 'Note which created this to-do item.', + description: 'Note which created the to-do item.', null: true field :member_access_type, GraphQL::Types::String, @@ -72,7 +72,7 @@ module Types null: true field :snoozed_until, Types::TimeType, - description: 'The time until when the todo is snoozed.', + description: 'Time until when the todo is snoozed.', null: true def project diff --git a/app/graphql/types/todoable_interface.rb b/app/graphql/types/todoable_interface.rb index 1b673848006..c7693b5ab53 100644 --- a/app/graphql/types/todoable_interface.rb +++ b/app/graphql/types/todoable_interface.rb @@ -9,12 +9,12 @@ module Types field :web_url, GraphQL::Types::String, null: true, - description: 'URL of this object.' + description: 'URL of the object.' field :name, GraphQL::Types::String, null: true, - description: 'Name or title of this object.' + description: 'Name or title of the object.' def self.resolve_type(object, context) case object diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index 712c9be3bac..292460df861 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -27,7 +27,7 @@ module Types field :username, type: GraphQL::Types::String, null: false, - description: 'Username of the user. Unique within this instance of GitLab.' + description: 'Username of the user. Unique within the instance of GitLab.' field :name, type: GraphQL::Types::String, null: false, diff --git a/app/graphql/types/user_merge_request_interaction_type.rb b/app/graphql/types/user_merge_request_interaction_type.rb index 07f48a276fc..843ff4d58b9 100644 --- a/app/graphql/types/user_merge_request_interaction_type.rb +++ b/app/graphql/types/user_merge_request_interaction_type.rb @@ -17,30 +17,30 @@ module Types null: false, calls_gitaly: true, method: :can_merge?, - description: 'Whether this user can merge this merge request.' + description: 'Whether the user can merge the merge request.' field :can_update, type: ::GraphQL::Types::Boolean, null: false, method: :can_update?, - description: 'Whether this user can update this merge request.' + description: 'Whether the user can update the merge request.' field :review_state, ::Types::MergeRequestReviewStateEnum, null: true, - description: 'State of the review by this user.' + description: 'State of the review by the user.' field :reviewed, type: ::GraphQL::Types::Boolean, null: false, method: :reviewed?, - description: 'Whether this user has provided a review for this merge request.' + description: 'Whether the user has provided a review for the merge request.' field :approved, type: ::GraphQL::Types::Boolean, null: false, method: :approved?, - description: 'Whether this user has approved this merge request.' + description: 'Whether the user has approved the merge request.' end end diff --git a/app/models/active_session.rb b/app/models/active_session.rb index 94397dd6966..e42313451e7 100644 --- a/app/models/active_session.rb +++ b/app/models/active_session.rb @@ -209,9 +209,7 @@ class ActiveSession session_keys.each_slice(SESSION_BATCH_SIZE).flat_map do |session_keys_batch| Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do raw_sessions = if Gitlab::Redis::ClusterUtil.cluster?(redis) - redis.with_readonly_pipeline do - Gitlab::Redis::ClusterUtil.batch_get(session_keys_batch, redis) - end + Gitlab::Redis::ClusterUtil.batch_get(session_keys_batch, redis) else redis.mget(session_keys_batch) end @@ -263,9 +261,7 @@ class ActiveSession found = Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do entry_keys = session_ids.map { |session_id| key_name(user_id, session_id) } entries = if Gitlab::Redis::ClusterUtil.cluster?(redis) - redis.with_readonly_pipeline do - Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis) - end + Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis) else redis.mget(entry_keys) end @@ -280,9 +276,7 @@ class ActiveSession fallbacks = Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do entry_keys = missing.map { |session_id| key_name_v1(user_id, session_id) } entries = if Gitlab::Redis::ClusterUtil.cluster?(redis) - redis.with_readonly_pipeline do - Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis) - end + Gitlab::Redis::ClusterUtil.batch_get(entry_keys, redis) else redis.mget(entry_keys) end diff --git a/app/models/repository.rb b/app/models/repository.rb index c8fb72c2458..0e42fa0847f 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -238,16 +238,20 @@ class Repository def has_ambiguous_refs? return false unless branch_names.present? && tag_names.present? - with_slash, no_slash = (branch_names + tag_names).partition { |ref| ref.include?('/') } + with_slash = [] + no_slash = [] + (branch_names + tag_names).each do |ref| + slash_index = ref.index('/') + if slash_index.present? + with_slash << ref.first(slash_index) + else + no_slash << ref + end + end return false if with_slash.empty? - prefixes = no_slash.map { |ref| Regexp.escape(ref) }.join('|') - prefix_regex = %r{^(#{prefixes})/} - - with_slash.any? do |ref| - prefix_regex.match?(ref) - end + with_slash.intersect?(no_slash) end cache_method :has_ambiguous_refs? diff --git a/app/models/work_item.rb b/app/models/work_item.rb index e1fac97b55b..86a7ad69b1b 100644 --- a/app/models/work_item.rb +++ b/app/models/work_item.rb @@ -31,6 +31,20 @@ class WorkItem < Issue includes(:author, :work_item_type, project: :project_feature) } + scope :within_timeframe, ->(start_date, due_date) do + date_filtered_issue_ids = ::WorkItems::DatesSource + .select('issue_id') + .where('start_date IS NOT NULL OR due_date IS NOT NULL') + # Require the namespace_ids CTE from by_parent to be present when filtering by timeframe + # for performance reasons. + # see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181904 + .where('namespace_id IN (SELECT id FROM namespace_ids)') + .where('start_date IS NULL OR start_date <= ?', due_date) + .where('due_date IS NULL OR due_date >= ?', start_date) + + joins("INNER JOIN (#{date_filtered_issue_ids.to_sql}) AS filtered_dates ON issues.id = filtered_dates.issue_id") + end + class << self def find_by_namespace_and_iid!(namespace, iid) find_by!(namespace: namespace, iid: iid) diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index ae9a8307eb9..55d1c7a2759 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -1,4 +1,4 @@ -- page_title _("Snippets") +- page_title s_("Snippets|Snippets") - new_project_snippet_link = new_project_snippet_path(@project) if can?(current_user, :create_snippet, @project) - if @snippets.exists? @@ -6,10 +6,10 @@ .top-area - include_private = @project.member?(current_user) || current_user.admin? = render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private, counts: @snippet_counts } - - if new_project_snippet_link.present? .nav-controls - = link_button_to _("New snippet"), new_project_snippet_link, title: _("New snippet"), variant: :confirm + = link_button_to s_("Snippets|New snippet"), new_project_snippet_link, title: s_("Snippets|New snippet"), variant: :confirm + = render 'shared/snippets/list' - else diff --git a/config/feature_flags/gitlab_com_derisk/use_primary_and_secondary_stores_for_sessions.yml b/config/feature_flags/gitlab_com_derisk/use_primary_and_secondary_stores_for_sessions.yml deleted file mode 100644 index a94f8ae3249..00000000000 --- a/config/feature_flags/gitlab_com_derisk/use_primary_and_secondary_stores_for_sessions.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: use_primary_and_secondary_stores_for_sessions -feature_issue_url: https://gitlab.com/gitlab-com/gl-infra/data-access/durability/team/-/issues/28 -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175735 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/509337 -milestone: '17.9' -group: group::durability -type: gitlab_com_derisk -default_enabled: false diff --git a/config/feature_flags/gitlab_com_derisk/use_primary_store_as_default_for_sessions.yml b/config/feature_flags/gitlab_com_derisk/use_primary_store_as_default_for_sessions.yml deleted file mode 100644 index c2f8b4b29dd..00000000000 --- a/config/feature_flags/gitlab_com_derisk/use_primary_store_as_default_for_sessions.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: use_primary_store_as_default_for_sessions -feature_issue_url: https://gitlab.com/gitlab-com/gl-infra/data-access/durability/team/-/issues/28 -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175735 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/509338 -milestone: '17.9' -group: group::durability -type: gitlab_com_derisk -default_enabled: false diff --git a/config/redis.yml.example b/config/redis.yml.example index 3f93434b263..20168985fd9 100644 --- a/config/redis.yml.example +++ b/config/redis.yml.example @@ -8,9 +8,6 @@ development: cache: cluster: - redis://localhost:7001 - cluster_sessions: - cluster: - - redis://localhost:7001 cluster_shared_state: cluster: - redis://localhost:7001 @@ -24,7 +21,8 @@ development: cluster: - redis://localhost:7001 sessions: - url: redis://localhost:6379 + cluster: + - redis://localhost:7001 shared_state: cluster: - redis://localhost:7001 @@ -40,9 +38,6 @@ test: cache: cluster: - redis://localhost:7001 - cluster_sessions: - cluster: - - redis://localhost:7001 cluster_shared_state: cluster: - redis://localhost:7001 @@ -55,15 +50,12 @@ test: queues_metadata: cluster: - redis://localhost:7001 + sessions: + cluster: + - redis://localhost:7001 shared_state: cluster: - redis://localhost:7001 - # Temporarily set sessions to use single Redis instance - # until we finish migration to cluster_sessions. https://gitlab.com/groups/gitlab-com/gl-infra/data-access/durability/-/epics/9 - # This helps specs to pass as-is, otherwise MultiStore writes - # to the same store in specs. - sessions: - url: redis://localhost:6379 # pubsub and workhorse are not redis-cluster compatible # even though they fall-back to shared_state workhorse: diff --git a/db/post_migrate/20250311113123_ensure_id_uniqueness_for_p_ci_runners.rb b/db/post_migrate/20250311113123_ensure_id_uniqueness_for_p_ci_runners.rb new file mode 100644 index 00000000000..9306ca9b5a6 --- /dev/null +++ b/db/post_migrate/20250311113123_ensure_id_uniqueness_for_p_ci_runners.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class EnsureIdUniquenessForPCiRunners < Gitlab::Database::Migration[2.2] + include Gitlab::Database::PartitioningMigrationHelpers::UniquenessHelpers + + milestone '17.10' + enable_lock_retries! + + TABLE_NAME = :ci_runners + SEQ_NAME = :ci_runners_id_seq + + def up + ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end + + def down + revert_ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end +end diff --git a/db/post_migrate/20250311113127_ensure_id_uniqueness_for_p_ci_runner_machines.rb b/db/post_migrate/20250311113127_ensure_id_uniqueness_for_p_ci_runner_machines.rb new file mode 100644 index 00000000000..5266d294763 --- /dev/null +++ b/db/post_migrate/20250311113127_ensure_id_uniqueness_for_p_ci_runner_machines.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class EnsureIdUniquenessForPCiRunnerMachines < Gitlab::Database::Migration[2.2] + include Gitlab::Database::PartitioningMigrationHelpers::UniquenessHelpers + + milestone '17.10' + enable_lock_retries! + + TABLE_NAME = :ci_runner_machines + SEQ_NAME = :ci_runner_machines_id_seq + + def up + ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end + + def down + revert_ensure_unique_id(TABLE_NAME, seq: SEQ_NAME) + end +end diff --git a/db/schema_migrations/20250311113123 b/db/schema_migrations/20250311113123 new file mode 100644 index 00000000000..36840c0dee0 --- /dev/null +++ b/db/schema_migrations/20250311113123 @@ -0,0 +1 @@ +e7f34db3fe34759c7391d31be4518fc38ef8e133975330d4e7f0995c4c27e129 \ No newline at end of file diff --git a/db/schema_migrations/20250311113127 b/db/schema_migrations/20250311113127 new file mode 100644 index 00000000000..56770a7b75e --- /dev/null +++ b/db/schema_migrations/20250311113127 @@ -0,0 +1 @@ +d771cbfc1b3b2c979e8f6bc3a4f3b21ac54e5e4f418ab93ef801329b4d6546ca \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 3abe2cd4e0c..93e5478d53b 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10,6 +10,19 @@ CREATE EXTENSION IF NOT EXISTS btree_gist; CREATE EXTENSION IF NOT EXISTS pg_trgm; +CREATE FUNCTION assign_ci_runner_machines_id_value() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."id" IS NOT NULL THEN + RAISE WARNING 'Manually assigning ids is not allowed, the value will be ignored'; +END IF; +NEW."id" := nextval('ci_runner_machines_id_seq'::regclass); +RETURN NEW; + +END +$$; + CREATE FUNCTION assign_ci_runner_taggings_id_value() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -23,6 +36,19 @@ RETURN NEW; END $$; +CREATE FUNCTION assign_ci_runners_id_value() RETURNS trigger + LANGUAGE plpgsql + AS $$ +BEGIN +IF NEW."id" IS NOT NULL THEN + RAISE WARNING 'Manually assigning ids is not allowed, the value will be ignored'; +END IF; +NEW."id" := nextval('ci_runners_id_seq'::regclass); +RETURN NEW; + +END +$$; + CREATE FUNCTION assign_p_ci_build_tags_id_value() RETURNS trigger LANGUAGE plpgsql AS $$ @@ -14686,7 +14712,7 @@ CREATE SEQUENCE group_ssh_certificates_id_seq ALTER SEQUENCE group_ssh_certificates_id_seq OWNED BY group_ssh_certificates.id; CREATE TABLE group_type_ci_runner_machines ( - id bigint DEFAULT nextval('ci_runner_machines_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, runner_id bigint NOT NULL, sharding_key_id bigint, created_at timestamp with time zone NOT NULL, @@ -14713,7 +14739,7 @@ CREATE TABLE group_type_ci_runner_machines ( ); CREATE TABLE group_type_ci_runners ( - id bigint DEFAULT nextval('ci_runners_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, creator_id bigint, sharding_key_id bigint, created_at timestamp with time zone, @@ -15283,7 +15309,7 @@ CREATE SEQUENCE instance_integrations_id_seq ALTER SEQUENCE instance_integrations_id_seq OWNED BY instance_integrations.id; CREATE TABLE instance_type_ci_runner_machines ( - id bigint DEFAULT nextval('ci_runner_machines_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, runner_id bigint NOT NULL, sharding_key_id bigint, created_at timestamp with time zone NOT NULL, @@ -15310,7 +15336,7 @@ CREATE TABLE instance_type_ci_runner_machines ( ); CREATE TABLE instance_type_ci_runners ( - id bigint DEFAULT nextval('ci_runners_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, creator_id bigint, sharding_key_id bigint, created_at timestamp with time zone, @@ -20558,7 +20584,7 @@ CREATE SEQUENCE project_topics_id_seq ALTER SEQUENCE project_topics_id_seq OWNED BY project_topics.id; CREATE TABLE project_type_ci_runner_machines ( - id bigint DEFAULT nextval('ci_runner_machines_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, runner_id bigint NOT NULL, sharding_key_id bigint, created_at timestamp with time zone NOT NULL, @@ -20585,7 +20611,7 @@ CREATE TABLE project_type_ci_runner_machines ( ); CREATE TABLE project_type_ci_runners ( - id bigint DEFAULT nextval('ci_runners_id_seq'::regclass) NOT NULL, + id bigint NOT NULL, creator_id bigint, sharding_key_id bigint, created_at timestamp with time zone, @@ -25805,14 +25831,10 @@ ALTER TABLE ONLY ci_resource_groups ALTER COLUMN id SET DEFAULT nextval('ci_reso ALTER TABLE ONLY ci_resources ALTER COLUMN id SET DEFAULT nextval('ci_resources_id_seq'::regclass); -ALTER TABLE ONLY ci_runner_machines ALTER COLUMN id SET DEFAULT nextval('ci_runner_machines_id_seq'::regclass); - ALTER TABLE ONLY ci_runner_namespaces ALTER COLUMN id SET DEFAULT nextval('ci_runner_namespaces_id_seq'::regclass); ALTER TABLE ONLY ci_runner_projects ALTER COLUMN id SET DEFAULT nextval('ci_runner_projects_id_seq'::regclass); -ALTER TABLE ONLY ci_runners ALTER COLUMN id SET DEFAULT nextval('ci_runners_id_seq'::regclass); - ALTER TABLE ONLY ci_running_builds ALTER COLUMN id SET DEFAULT nextval('ci_running_builds_id_seq'::regclass); ALTER TABLE ONLY ci_secure_file_states ALTER COLUMN ci_secure_file_id SET DEFAULT nextval('ci_secure_file_states_ci_secure_file_id_seq'::regclass); @@ -38907,8 +38929,12 @@ ALTER INDEX p_ci_builds_token_encrypted_partition_id_idx ATTACH PARTITION unique CREATE TRIGGER ai_conversation_threads_loose_fk_trigger AFTER DELETE ON ai_conversation_threads REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records(); +CREATE TRIGGER assign_ci_runner_machines_id_trigger BEFORE INSERT ON ci_runner_machines FOR EACH ROW EXECUTE FUNCTION assign_ci_runner_machines_id_value(); + CREATE TRIGGER assign_ci_runner_taggings_id_trigger BEFORE INSERT ON ci_runner_taggings FOR EACH ROW EXECUTE FUNCTION assign_ci_runner_taggings_id_value(); +CREATE TRIGGER assign_ci_runners_id_trigger BEFORE INSERT ON ci_runners FOR EACH ROW EXECUTE FUNCTION assign_ci_runners_id_value(); + CREATE TRIGGER assign_p_ci_build_tags_id_trigger BEFORE INSERT ON p_ci_build_tags FOR EACH ROW EXECUTE FUNCTION assign_p_ci_build_tags_id_value(); CREATE TRIGGER assign_p_ci_builds_execution_configs_id_trigger BEFORE INSERT ON p_ci_builds_execution_configs FOR EACH ROW EXECUTE FUNCTION assign_p_ci_builds_execution_configs_id_value(); diff --git a/doc/administration/raketasks/ldap.md b/doc/administration/raketasks/ldap.md index 382eeb1e5ed..184fc5d0cd7 100644 --- a/doc/administration/raketasks/ldap.md +++ b/doc/administration/raketasks/ldap.md @@ -21,17 +21,25 @@ The LDAP check Rake task tests the `bind_dn` and `password` credentials executed as part of the `gitlab:check` task, but can run independently using the command below. -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:check - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:check +``` - ```shell - sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:check +``` + +{{< /tab >}} + +{{< /tabs >}} By default, the task returns a sample of 100 LDAP users. Change this limit by passing a number to the check task: @@ -61,17 +69,25 @@ instead. {{< /alert >}} -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:group_sync - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:group_sync +``` - ```shell - bundle exec rake gitlab:ldap:group_sync - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:group_sync +``` + +{{< /tab >}} + +{{< /tabs >}} ## Rename a provider @@ -103,17 +119,25 @@ correct provider as the `new_provider`. {{< /alert >}} -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:rename_provider[old_provider,new_provider] - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:rename_provider[old_provider,new_provider] +``` - ```shell - bundle exec rake gitlab:ldap:rename_provider[old_provider,new_provider] RAILS_ENV=production - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:rename_provider[old_provider,new_provider] +``` + +{{< /tab >}} + +{{< /tabs >}} ### Example @@ -140,17 +164,25 @@ User identities were successfully updated If you do not specify an `old_provider` and `new_provider` the task prompts you for them: -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:rename_provider - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:rename_provider +``` - ```shell - bundle exec rake gitlab:ldap:rename_provider RAILS_ENV=production - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:rename_provider +``` + +{{< /tab >}} + +{{< /tabs >}} **Example output:** @@ -175,17 +207,25 @@ The following Rake tasks are provided for updating the contents of the encrypted Show the contents of the current LDAP secrets. -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:secret:show - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:secret:show +``` - ```shell - bundle exec rake gitlab:ldap:secret:show RAILS_ENV=production - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:secret:show +``` + +{{< /tab >}} + +{{< /tabs >}} **Example output:** @@ -199,33 +239,49 @@ main: Opens the secret contents in your editor, and writes the resulting content to the encrypted secret file when you exit. -- Linux package installations: +{{< tabs >}} - ```shell - sudo gitlab-rake gitlab:ldap:secret:edit EDITOR=vim - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +sudo gitlab-rake gitlab:ldap:secret:edit EDITOR=vim +``` - ```shell - bundle exec rake gitlab:ldap:secret:edit RAILS_ENV=production EDITOR=vim - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production EDITOR=vim -u git -H bundle exec rake gitlab:ldap:secret:edit +``` + +{{< /tab >}} + +{{< /tabs >}} ### Write raw secret Write new secret content by providing it on STDIN. -- Linux package installations: +{{< tabs >}} - ```shell - echo -e "main:\n password: '123'" | sudo gitlab-rake gitlab:ldap:secret:write - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +echo -e "main:\n password: '123'" | sudo gitlab-rake gitlab:ldap:secret:write +``` - ```shell - echo -e "main:\n password: '123'" | bundle exec rake gitlab:ldap:secret:write RAILS_ENV=production - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +echo -e "main:\n password: '123'" | sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:ldap:secret:write +``` + +{{< /tab >}} + +{{< /tabs >}} ### Secrets examples diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md index 7aac817d11e..b461cd89c55 100644 --- a/doc/administration/raketasks/uploads/migrate.md +++ b/doc/administration/raketasks/uploads/migrate.md @@ -36,17 +36,25 @@ These [individual Rake tasks](#individual-rake-tasks) are described in the next To migrate all uploads from local storage to object storage, run: -- Linux package installations: +{{< tabs >}} - ```shell - gitlab-rake "gitlab:uploads:migrate:all" - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +gitlab-rake "gitlab:uploads:migrate:all" +``` - ```shell - sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all +``` + +{{< /tab >}} + +{{< /tabs >}} You can optionally track progress and verify that all uploads migrated successfully using the [PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database): @@ -189,19 +197,27 @@ tasks to migrate files falling under each of these categories one by one. For details on these Rake tasks, refer to [Individual Rake tasks](#individual-rake-tasks). Keep in mind the task name in this case is `gitlab:uploads:migrate_to_local`. -To migrate uploads from object storage to local storage, run the following Rake task: +To migrate uploads from object storage to local storage: -- Linux package installations: +{{< tabs >}} - ```shell - gitlab-rake "gitlab:uploads:migrate_to_local:all" - ``` +{{< tab title="Linux package (Omnibus)" >}} -- Self-compiled installations: +```shell +gitlab-rake "gitlab:uploads:migrate_to_local:all" +``` - ```shell - sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate_to_local:all - ``` +{{< /tab >}} + +{{< tab title="Self-compiled (source)" >}} + +```shell +sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate_to_local:all +``` + +{{< /tab >}} + +{{< /tabs >}} After running the Rake task, you can disable object storage by undoing the changes described in the instructions to [configure object storage](../../uploads.md#using-object-storage). diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md index 7b8f3d1d131..637beca381c 100644 --- a/doc/administration/reference_architectures/25k_users.md +++ b/doc/administration/reference_architectures/25k_users.md @@ -165,7 +165,7 @@ Before starting, see the [requirements](_index.md#requirements) for reference ar ## Testing methodology -The 500 RPS / 2k user reference architecture is designed to accommodate most common workflows. The [Framework](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/gitlab-delivery/framework/) team regularly conducts smoke and performance testing against the following endpoint throughput targets: +The 500 RPS / 25k user reference architecture is designed to accommodate most common workflows. The [Framework](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/gitlab-delivery/framework/) team regularly conducts smoke and performance testing against the following endpoint throughput targets: | Endpoint type | Target throughput | | ------------- | ----------------- | diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md index 48bcb5276d1..55655e09e4a 100644 --- a/doc/administration/reference_architectures/3k_users.md +++ b/doc/administration/reference_architectures/3k_users.md @@ -157,7 +157,7 @@ Before proceeding, review the [requirements](_index.md#requirements) for the ref ## Testing methodology -The 60 RPS / 5k user reference architecture is designed to accommodate most common workflows. The [Framework](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/gitlab-delivery/framework/) team regularly conducts smoke and performance testing against the following endpoint throughput targets: +The 60 RPS / 3k user reference architecture is designed to accommodate most common workflows. The [Framework](https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/gitlab-delivery/framework/) team regularly conducts smoke and performance testing against the following endpoint throughput targets: | Endpoint type | Target throughput | | ------------- | ----------------- | diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index 41fcdd2e7f8..283a8c57bac 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -11436,21 +11436,21 @@ Input type: `UpdateNamespacePackageSettingsInput` | `auditEventsEnabled` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.10. | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `genericDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. | +| `genericDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate generic packages are allowed for the namespace. | | `lockMavenPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether Maven package forwarding is locked for all descendent namespaces. | | `lockNpmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is locked for all descendent namespaces. | | `lockPypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is locked for all descendent namespaces. | | `mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `mavenDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. | -| `mavenPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether Maven package forwarding is allowed for this namespace. | +| `mavenDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Maven packages are allowed for the namespace. | +| `mavenPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether Maven package forwarding is allowed for the namespace. | | `namespacePath` | [`ID!`](#id) | Namespace path where the namespace package setting is located. | -| `npmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is allowed for this namespace. | +| `npmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is allowed for the namespace. | | `nugetDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When nuget_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `nugetDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate NuGet packages are allowed for this namespace. | -| `nugetSymbolServerEnabled` | [`Boolean`](#boolean) | Indicates whether the NuGet symbol server is enabled for this namespace. | -| `pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for this namespace. | +| `nugetDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate NuGet packages are allowed for the namespace. | +| `nugetSymbolServerEnabled` | [`Boolean`](#boolean) | Indicates whether the NuGet symbol server is enabled for the namespace. | +| `pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for the namespace. | | `terraformModuleDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When terraform_module_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `terraformModuleDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Terraform packages are allowed for this namespace. | +| `terraformModuleDuplicatesAllowed` | [`Boolean`](#boolean) | Indicates whether duplicate Terraform packages are allowed for the namespace. | #### Fields @@ -19912,7 +19912,7 @@ A user with add-on data. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -20559,12 +20559,12 @@ Describes an alert from the project's Alert Management. | Name | Type | Description | | ---- | ---- | ----------- | | `assignees` | [`UserCoreConnection`](#usercoreconnection) | Assignees of the alert. (see [Connections](#connections)) | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `createdAt` | [`Time`](#time) | Timestamp the alert was created. | | `description` | [`String`](#string) | Description of the alert. | | `details` | [`JSON`](#json) | Alert details. | | `detailsUrl` | [`String!`](#string) | URL of the alert detail page. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `endedAt` | [`Time`](#time) | Timestamp the alert ended. | | `environment` | [`Environment`](#environment) | Environment for the alert. | | `eventCount` | [`Int`](#int) | Number of events of the alert. | @@ -20575,7 +20575,7 @@ Describes an alert from the project's Alert Management. | `issueIid` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 13.10. Use issue field. | | `metricsDashboardUrl` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 16.0. Returns no data. Underlying feature was removed in 16.0. | | `monitoringTool` | [`String`](#string) | Monitoring tool the alert came from. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `prometheusAlert` {{< icon name="warning-solid" >}} | [`PrometheusAlert`](#prometheusalert) | **Deprecated** in GitLab 17.3. Returns no data. Underlying feature was removed in 16.0. | | `runbook` | [`String`](#string) | Runbook for the alert as defined in alert details. | | `service` | [`String`](#string) | Service the alert came from. | @@ -20949,7 +20949,7 @@ Core representation of a GitLab user. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -21501,7 +21501,7 @@ Represents an epic on an issue board. | `blockingCount` | [`Int`](#int) | Count of epics that this epic is blocking. | | `closedAt` | [`Time`](#time) | Timestamp of when the epic was closed. | | `color` | [`String`](#string) | Color of the epic. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. | | `createdAt` | [`Time`](#time) | Timestamp of when the epic was created. | | `defaultProjectForIssueCreation` | [`Project`](#project) | Default Project for issue creation. Based on the project the user created the last issue in. | @@ -21509,7 +21509,7 @@ Represents an epic on an issue board. | `descendantWeightSum` | [`EpicDescendantWeights`](#epicdescendantweights) | Total weight of open and closed issues in the epic and its descendants. | | `description` | [`String`](#string) | Description of the epic. | | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `downvotes` | [`Int!`](#int) | Number of downvotes the epic has received. | | `dueDate` | [`Time`](#time) | Due date of the epic. | | `dueDateFixed` | [`Time`](#time) | Fixed due date of the epic. | @@ -21527,7 +21527,7 @@ Represents an epic on an issue board. | `iid` | [`String!`](#string) | Internal ID of the epic. | | `issues` | [`EpicIssueConnection`](#epicissueconnection) | A list of issues associated with the epic. (see [Connections](#connections)) | | `labels` | [`LabelConnection`](#labelconnection) | Labels assigned to the epic. (see [Connections](#connections)) | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `parent` | [`Epic`](#epic) | Parent epic of the epic. | | `participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants for the epic. (see [Connections](#connections)) | | `relationPath` | [`String`](#string) | URI path of the epic-issue relationship. | @@ -21773,7 +21773,7 @@ Branch protection details for a branch rule. | `codeOwnerApprovalRequired` | [`Boolean!`](#boolean) | Enforce code owner approvals before allowing a merge. | | `mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when the branch is the source branch. (see [Connections](#connections)) | | `pushAccessLevels` | [`PushAccessLevelConnection`](#pushaccesslevelconnection) | Details about who can push when the branch is the source branch. (see [Connections](#connections)) | -| `unprotectAccessLevels` | [`UnprotectAccessLevelConnection`](#unprotectaccesslevelconnection) | Details about who can unprotect this branch. (see [Connections](#connections)) | +| `unprotectAccessLevels` | [`UnprotectAccessLevelConnection`](#unprotectaccesslevelconnection) | Details about who can unprotect the branch. (see [Connections](#connections)) | ### `BranchRule` @@ -21784,13 +21784,13 @@ Branch rules configured for a rule target. | Name | Type | Description | | ---- | ---- | ----------- | | `approvalRules` | [`ApprovalProjectRuleConnection`](#approvalprojectruleconnection) | Merge request approval rules configured for this branch rule. (see [Connections](#connections)) | -| `branchProtection` | [`BranchProtection`](#branchprotection) | Branch protections configured for this branch rule. | +| `branchProtection` | [`BranchProtection`](#branchprotection) | Branch protections configured for the branch rule. | | `createdAt` | [`Time`](#time) | Timestamp of when the branch rule was created. | | `externalStatusChecks` | [`ExternalStatusCheckConnection`](#externalstatuscheckconnection) | External status checks configured for this branch rule. (see [Connections](#connections)) | | `id` | [`ProjectsBranchRuleID`](#projectsbranchruleid) | ID of the branch rule. | -| `isDefault` | [`Boolean!`](#boolean) | Check if this branch rule protects the project's default branch. | -| `isProtected` | [`Boolean!`](#boolean) | Check if this branch rule protects access for the branch. | -| `matchingBranchesCount` | [`Int!`](#int) | Number of existing branches that match this branch rule. | +| `isDefault` | [`Boolean!`](#boolean) | Check if the branch rule protects the project's default branch. | +| `isProtected` | [`Boolean!`](#boolean) | Check if the branch rule protects access for the branch. | +| `matchingBranchesCount` | [`Int!`](#int) | Number of existing branches that match the branch rule. | | `name` | [`String!`](#string) | Name of the branch rule target. Includes wildcards. | | `squashOption` {{< icon name="warning-solid" >}} | [`SquashOption`](#squashoption) | **Introduced** in GitLab 17.9. **Status**: Experiment. The default behavior for squashing in merge requests. Returns null if `branch_rule_squash_settings` feature flag is disabled. | | `updatedAt` | [`Time`](#time) | Timestamp of when the branch rule was last updated. | @@ -23005,7 +23005,7 @@ Represents a summary of the compared codequality report. | `fullTitleHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `full_title`. | | `id` | [`ID!`](#id) | ID (global ID) of the commit. | | `message` | [`String`](#string) | Raw commit message. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `sha` | [`String!`](#string) | SHA1 ID of the commit. | | `shortId` | [`String!`](#string) | Short SHA1 ID of the commit. | | `signature` | [`CommitSignature`](#commitsignature) | Signature of the commit. | @@ -23690,7 +23690,7 @@ The currently authenticated GitLab user. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -24832,11 +24832,11 @@ A single design. | Name | Type | Description | | ---- | ---- | ----------- | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `description` | [`String`](#string) | Description of the design. | | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | | `diffRefs` | [`DiffRefs!`](#diffrefs) | Diff refs for the design. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `event` | [`DesignVersionEvent!`](#designversionevent) | How the design was changed in the current version. | | `filename` | [`String!`](#string) | Filename of the design. | | `fullPath` | [`ID!`](#id) | Full path to the design file. | @@ -24846,7 +24846,7 @@ A single design. | `imported` | [`Boolean!`](#boolean) | Indicates whether the design was imported. | | `importedFrom` | [`ImportSource!`](#importsource) | Import source of the design. | | `issue` | [`Issue!`](#issue) | Issue the design belongs to. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `notesCount` | [`Int!`](#int) | Total count of user-created notes for the design. | | `project` | [`Project!`](#project) | Project the design belongs to. | | `webUrl` | [`String!`](#string) | URL of the design. | @@ -25527,7 +25527,7 @@ Represents an epic. | `blockingCount` | [`Int`](#int) | Count of epics that this epic is blocking. | | `closedAt` | [`Time`](#time) | Timestamp of when the epic was closed. | | `color` | [`String`](#string) | Color of the epic. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. | | `createdAt` | [`Time`](#time) | Timestamp of when the epic was created. | | `defaultProjectForIssueCreation` | [`Project`](#project) | Default Project for issue creation. Based on the project the user created the last issue in. | @@ -25535,7 +25535,7 @@ Represents an epic. | `descendantWeightSum` | [`EpicDescendantWeights`](#epicdescendantweights) | Total weight of open and closed issues in the epic and its descendants. | | `description` | [`String`](#string) | Description of the epic. | | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `downvotes` | [`Int!`](#int) | Number of downvotes the epic has received. | | `dueDate` | [`Time`](#time) | Due date of the epic. | | `dueDateFixed` | [`Time`](#time) | Fixed due date of the epic. | @@ -25553,7 +25553,7 @@ Represents an epic. | `iid` | [`String!`](#string) | Internal ID of the epic. | | `issues` | [`EpicIssueConnection`](#epicissueconnection) | A list of issues associated with the epic. (see [Connections](#connections)) | | `labels` | [`LabelConnection`](#labelconnection) | Labels assigned to the epic. (see [Connections](#connections)) | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `parent` | [`Epic`](#epic) | Parent epic of the epic. | | `participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants for the epic. (see [Connections](#connections)) | | `relationPath` | [`String`](#string) | URI path of the epic-issue relationship. | @@ -25800,12 +25800,12 @@ Relationship between an epic and an issue. | `assignees` | [`UserCoreConnection`](#usercoreconnection) | Assignees of the issue. (see [Connections](#connections)) | | `author` | [`UserCore!`](#usercore) | User that created the issue. | | `blocked` | [`Boolean!`](#boolean) | Indicates the issue is blocked. | -| `blockedByCount` | [`Int`](#int) | Count of issues blocking this issue. | -| `blockedByIssues` | [`IssueConnection`](#issueconnection) | Issues blocking this issue. (see [Connections](#connections)) | -| `blockingCount` | [`Int!`](#int) | Count of issues this issue is blocking. | +| `blockedByCount` | [`Int`](#int) | Count of issues blocking the issue. | +| `blockedByIssues` | [`IssueConnection`](#issueconnection) | Issues blocking the issue. (see [Connections](#connections)) | +| `blockingCount` | [`Int!`](#int) | Count of issues the issue is blocking. | | `closedAsDuplicateOf` | [`Issue`](#issue) | Issue the issue was closed as a duplicate of. | | `closedAt` | [`Time`](#time) | Timestamp of when the issue was closed. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `confidential` | [`Boolean!`](#boolean) | Indicates the issue is confidential. | | `createNoteEmail` | [`String`](#string) | User specific email address for the issue. | | `createdAt` | [`Time!`](#time) | Timestamp of when the issue was created. | @@ -25814,7 +25814,7 @@ Relationship between an epic and an issue. | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | | `designCollection` | [`DesignCollection`](#designcollection) | Collection of design images associated with the issue. | | `discussionLocked` | [`Boolean!`](#boolean) | Indicates discussion is locked on the issue. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `downvotes` | [`Int!`](#int) | Number of downvotes the issue has received. | | `dueDate` | [`Time`](#time) | Due date of the issue. | | `emailsDisabled` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Deprecated** in GitLab 16.3. Use `emails_enabled`. | @@ -25839,7 +25839,7 @@ Relationship between an epic and an issue. | `milestone` | [`Milestone`](#milestone) | Milestone of the issue. | | `moved` | [`Boolean`](#boolean) | Indicates if issue got moved from other project. | | `movedTo` | [`Issue`](#issue) | Updated Issue after it got moved to another project. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants in the issue. (see [Connections](#connections)) | | `projectId` | [`Int`](#int) | ID of the issue project. | | `relatedMergeRequests` | [`MergeRequestConnection`](#mergerequestconnection) | Merge requests related to the issue. This field can only be resolved for one issue in any single request. (see [Connections](#connections)) | @@ -28351,6 +28351,7 @@ Returns [`WorkItemStateCountsType`](#workitemstatecountstype). | `sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. | | `state` | [`IssuableState`](#issuablestate) | Current state of the work item. | | `subscribed` | [`SubscriptionStatus`](#subscriptionstatus) | Work items the current user is subscribed to. | +| `timeframe` | [`Timeframe`](#timeframe) | List items overlapping the given timeframe. | | `types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. | | `updatedAfter` | [`Time`](#time) | Work items updated after the timestamp. | | `updatedBefore` | [`Time`](#time) | Work items updated before the timestamp. | @@ -28421,6 +28422,7 @@ four standard [pagination arguments](#pagination-arguments): | `sort` | [`WorkItemSort`](#workitemsort) | Sort work items by criteria. | | `state` | [`IssuableState`](#issuablestate) | Current state of the work item. | | `subscribed` | [`SubscriptionStatus`](#subscriptionstatus) | Work items the current user is subscribed to. | +| `timeframe` | [`Timeframe`](#timeframe) | List items overlapping the given timeframe. | | `types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. | | `updatedAfter` | [`Time`](#time) | Work items updated after the timestamp. | | `updatedBefore` | [`Time`](#time) | Work items updated before the timestamp. | @@ -29148,12 +29150,12 @@ Describes an issuable resource link for incident issues. | `assignees` | [`UserCoreConnection`](#usercoreconnection) | Assignees of the issue. (see [Connections](#connections)) | | `author` | [`UserCore!`](#usercore) | User that created the issue. | | `blocked` | [`Boolean!`](#boolean) | Indicates the issue is blocked. | -| `blockedByCount` | [`Int`](#int) | Count of issues blocking this issue. | -| `blockedByIssues` | [`IssueConnection`](#issueconnection) | Issues blocking this issue. (see [Connections](#connections)) | -| `blockingCount` | [`Int!`](#int) | Count of issues this issue is blocking. | +| `blockedByCount` | [`Int`](#int) | Count of issues blocking the issue. | +| `blockedByIssues` | [`IssueConnection`](#issueconnection) | Issues blocking the issue. (see [Connections](#connections)) | +| `blockingCount` | [`Int!`](#int) | Count of issues the issue is blocking. | | `closedAsDuplicateOf` | [`Issue`](#issue) | Issue the issue was closed as a duplicate of. | | `closedAt` | [`Time`](#time) | Timestamp of when the issue was closed. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `confidential` | [`Boolean!`](#boolean) | Indicates the issue is confidential. | | `createNoteEmail` | [`String`](#string) | User specific email address for the issue. | | `createdAt` | [`Time!`](#time) | Timestamp of when the issue was created. | @@ -29162,7 +29164,7 @@ Describes an issuable resource link for incident issues. | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | | `designCollection` | [`DesignCollection`](#designcollection) | Collection of design images associated with the issue. | | `discussionLocked` | [`Boolean!`](#boolean) | Indicates discussion is locked on the issue. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `downvotes` | [`Int!`](#int) | Number of downvotes the issue has received. | | `dueDate` | [`Time`](#time) | Due date of the issue. | | `emailsDisabled` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Deprecated** in GitLab 16.3. Use `emails_enabled`. | @@ -29186,7 +29188,7 @@ Describes an issuable resource link for incident issues. | `milestone` | [`Milestone`](#milestone) | Milestone of the issue. | | `moved` | [`Boolean`](#boolean) | Indicates if issue got moved from other project. | | `movedTo` | [`Issue`](#issue) | Updated Issue after it got moved to another project. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `participants` | [`UserCoreConnection`](#usercoreconnection) | List of participants in the issue. (see [Connections](#connections)) | | `projectId` | [`Int`](#int) | ID of the issue project. | | `relatedMergeRequests` | [`MergeRequestConnection`](#mergerequestconnection) | Merge requests related to the issue. This field can only be resolved for one issue in any single request. (see [Connections](#connections)) | @@ -29537,9 +29539,9 @@ Represents an SSH key. | `expiresAt` | [`Time!`](#time) | Timestamp of when the key expires. It's null if it never expires. | | `id` | [`ID!`](#id) | ID of the key. | | `key` | [`String!`](#string) | Public key of the key pair. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `title` | [`String!`](#string) | Title of the key. | -| `webUrl` | [`String`](#string) | URL of this object. | +| `webUrl` | [`String`](#string) | URL of the object. | ### `KubernetesAnnotation` @@ -29760,8 +29762,8 @@ Defines which user roles, users, or groups can merge into a protected branch. | ---- | ---- | ----------- | | `accessLevel` | [`Int!`](#int) | GitLab::Access level. | | `accessLevelDescription` | [`String!`](#string) | Human readable representation for the access level. | -| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. | -| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. | +| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with the access level. | +| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with the access level. | ### `MergeRequest` @@ -29787,7 +29789,7 @@ Defines which user roles, users, or groups can merge into a protected branch. | `changeRequesters` | [`UserCoreConnection`](#usercoreconnection) | Users that have requested changes to the merge request. (see [Connections](#connections)) | | `closedAt` | [`Time`](#time) | Timestamp of when the merge request was closed, null if not closed. | | `codequalityReportsComparer` | [`CodequalityReportsComparer`](#codequalityreportscomparer) | Code quality reports comparison reported on the merge request. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `commitCount` | [`Int`](#int) | Number of commits in the merge request. | | `commits` | [`CommitConnection`](#commitconnection) | Merge request commits. (see [Connections](#connections)) | | `commitsWithoutMergeCommits` | [`CommitConnection`](#commitconnection) | Merge request commits excluding merge commits. (see [Connections](#connections)) | @@ -29803,7 +29805,7 @@ Defines which user roles, users, or groups can merge into a protected branch. | `diffRefs` | [`DiffRefs`](#diffrefs) | References of the base SHA, the head SHA, and the start SHA for the merge request. | | `diffStatsSummary` | [`DiffStatsSummary`](#diffstatssummary) | Summary of which files were changed in the merge request. | | `discussionLocked` | [`Boolean!`](#boolean) | Indicates if comments on the merge request are locked to members only. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `divergedFromTargetBranch` | [`Boolean!`](#boolean) | Indicates if the source branch is behind the target branch. | | `downvotes` | [`Int!`](#int) | Number of downvotes for the merge request. | | `draft` | [`Boolean!`](#boolean) | Indicates if the merge request is a draft. | @@ -29835,7 +29837,7 @@ Defines which user roles, users, or groups can merge into a protected branch. | `mergeableDiscussionsState` | [`Boolean`](#boolean) | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged. | | `mergedAt` | [`Time`](#time) | Timestamp of when the merge request was merged, null if not merged. | | `milestone` | [`Milestone`](#milestone) | Milestone of the merge request. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `participants` | [`MergeRequestParticipantConnection`](#mergerequestparticipantconnection) | Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes. (see [Connections](#connections)) | | `policiesOverridingApprovalSettings` | [`[PolicyApprovalSettingsOverride!]`](#policyapprovalsettingsoverride) | Approval settings that are overridden by the policies for the merge request. | | `policyViolations` | [`PolicyViolationDetails`](#policyviolationdetails) | Policy violations reported on the merge request. | @@ -30039,7 +30041,7 @@ A user assigned to a merge request. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -30456,7 +30458,7 @@ The author of the merge request. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -30924,7 +30926,7 @@ A user participating in a merge request. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -31360,7 +31362,7 @@ A user assigned to a merge request as a reviewer. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -32094,7 +32096,7 @@ Product analytics events for a specific month and year. | `totalRepositorySizeExcess` | [`Float`](#float) | Total excess repository size of all projects in the root namespace in bytes. This only applies to namespaces under Project limit enforcement. | | `userPermissions` | [`NamespacePermissions!`](#namespacepermissions) | Permissions for the current user on the resource. | | `visibility` | [`String`](#string) | Visibility of the namespace. | -| `webUrl` | [`String`](#string) | URL of this object. | +| `webUrl` | [`String`](#string) | URL of the object. | #### Fields with arguments @@ -32918,7 +32920,7 @@ Represents a package details in the Package Registry. | `createdAt` | [`Time!`](#time) | Date of creation. | | `dependencyLinks` | [`PackageDependencyLinkConnection`](#packagedependencylinkconnection) | Dependency link. (see [Connections](#connections)) | | `id` | [`PackagesPackageID!`](#packagespackageid) | ID of the package. | -| `lastDownloadedAt` | [`Time`](#time) | Last time that a file of this package was downloaded. | +| `lastDownloadedAt` | [`Time`](#time) | Last time that a file of the package was downloaded. | | `mavenUrl` | [`String`](#string) | Url of the Maven project endpoint. | | `metadata` | [`PackageMetadata`](#packagemetadata) | Package metadata. | | `name` | [`String!`](#string) | Name of the package. | @@ -33071,23 +33073,23 @@ Namespace-level Package Registry settings. | ---- | ---- | ----------- | | `auditEventsEnabled` {{< icon name="warning-solid" >}} | [`Boolean`](#boolean) | **Introduced** in GitLab 17.10. **Status**: Experiment. Indicates whether audit events are created when publishing or deleting a package in the namespace (Premium and Ultimate only). Returns `null` if `package_registry_audit_events` feature flag is disabled. | | `genericDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `genericDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate generic packages are allowed for this namespace. | +| `genericDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate generic packages are allowed for the namespace. | | `lockMavenPackageRequestsForwarding` | [`Boolean!`](#boolean) | Indicates whether Maven package forwarding is locked for all descendent namespaces. | | `lockNpmPackageRequestsForwarding` | [`Boolean!`](#boolean) | Indicates whether npm package forwarding is locked for all descendent namespaces. | | `lockPypiPackageRequestsForwarding` | [`Boolean!`](#boolean) | Indicates whether PyPI package forwarding is locked for all descendent namespaces. | | `mavenDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `mavenDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Maven packages are allowed for this namespace. | -| `mavenPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether Maven package forwarding is allowed for this namespace. | +| `mavenDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Maven packages are allowed for the namespace. | +| `mavenPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether Maven package forwarding is allowed for the namespace. | | `mavenPackageRequestsForwardingLocked` | [`Boolean!`](#boolean) | Indicates whether Maven package forwarding settings are locked by a parent namespace. | -| `npmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is allowed for this namespace. | +| `npmPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether npm package forwarding is allowed for the namespace. | | `npmPackageRequestsForwardingLocked` | [`Boolean!`](#boolean) | Indicates whether npm package forwarding settings are locked by a parent namespace. | | `nugetDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When nuget_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `nugetDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate NuGet packages are allowed for this namespace. | -| `nugetSymbolServerEnabled` | [`Boolean!`](#boolean) | Indicates whether the NuGet symbol server is enabled for this namespace. | -| `pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for this namespace. | +| `nugetDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate NuGet packages are allowed for the namespace. | +| `nugetSymbolServerEnabled` | [`Boolean!`](#boolean) | Indicates whether the NuGet symbol server is enabled for the namespace. | +| `pypiPackageRequestsForwarding` | [`Boolean`](#boolean) | Indicates whether PyPI package forwarding is allowed for the namespace. | | `pypiPackageRequestsForwardingLocked` | [`Boolean!`](#boolean) | Indicates whether PyPI package forwarding settings are locked by a parent namespace. | | `terraformModuleDuplicateExceptionRegex` | [`UntrustedRegexp`](#untrustedregexp) | When terraform_module_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect. | -| `terraformModuleDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Terraform packages are allowed for this namespace. | +| `terraformModuleDuplicatesAllowed` | [`Boolean!`](#boolean) | Indicates whether duplicate Terraform packages are allowed for the namespace. | ### `PackageTag` @@ -33111,7 +33113,7 @@ A packages cleanup policy designed to keep only packages and packages assets tha | Name | Type | Description | | ---- | ---- | ----------- | | `keepNDuplicatedPackageFiles` | [`PackagesCleanupKeepDuplicatedPackageFilesEnum!`](#packagescleanupkeepduplicatedpackagefilesenum) | Number of duplicated package files to retain. | -| `nextRunAt` | [`Time`](#time) | Next time that this packages cleanup policy will be executed. | +| `nextRunAt` | [`Time`](#time) | Next time that the packages cleanup policy will be executed. | ### `PackagesProtectionRule` @@ -33944,7 +33946,7 @@ Project-level settings for product analytics provider. | `duoWorkflowStatusCheck` {{< icon name="warning-solid" >}} | [`DuoWorkflowEnablement`](#duoworkflowenablement) | **Introduced** in GitLab 17.7. **Status**: Experiment. Indicates whether GitLab Duo Workflow is enabled for the project. | | `exploreCatalogPath` {{< icon name="warning-solid" >}} | [`String`](#string) | **Introduced** in GitLab 17.6. **Status**: Experiment. Path to the project catalog resource. | | `flowMetrics` {{< icon name="warning-solid" >}} | [`ProjectValueStreamAnalyticsFlowMetrics`](#projectvaluestreamanalyticsflowmetrics) | **Introduced** in GitLab 15.10. **Status**: Experiment. Flow metrics for value stream analytics. | -| `forkedFrom` | [`Project`](#project) | Project this project was forked from. | +| `forkedFrom` | [`Project`](#project) | Project the project was forked from. | | `forkingAccessLevel` | [`ProjectFeatureAccess`](#projectfeatureaccess) | Access level required for forking access. | | `forksCount` | [`Int!`](#int) | Number of times the project has been forked. | | `fullPath` | [`ID!`](#id) | Full path of the project. | @@ -33968,7 +33970,7 @@ Project-level settings for product analytics provider. | `lastActivityAt` | [`Time`](#time) | Timestamp of the project last activity. | | `lfsEnabled` | [`Boolean`](#boolean) | Indicates if the project has Large File Storage (LFS) enabled. | | `markedForDeletionOn` {{< icon name="warning-solid" >}} | [`Time`](#time) | **Introduced** in GitLab 16.10. **Status**: Experiment. Date when project was scheduled to be deleted. | -| `maxAccessLevel` | [`AccessLevel!`](#accesslevel) | The maximum access level of the current user in the project. | +| `maxAccessLevel` | [`AccessLevel!`](#accesslevel) | Maximum access level of the current user in the project. | | `mergeCommitTemplate` | [`String`](#string) | Template used to create merge commit message in merge requests. | | `mergeRequestsAccessLevel` | [`ProjectFeatureAccess`](#projectfeatureaccess) | Access level required for merge requests access. | | `mergeRequestsDisableCommittersApproval` | [`Boolean!`](#boolean) | Indicates that committers of the given merge request cannot approve. | @@ -35069,7 +35071,7 @@ four standard [pagination arguments](#pagination-arguments): ##### `Project.label` -Label available on this project. +Label available on the project. Returns [`Label`](#label). @@ -36726,8 +36728,8 @@ Defines which user roles, users, or groups can push to a protected branch. | `accessLevel` | [`Int!`](#int) | GitLab::Access level. | | `accessLevelDescription` | [`String!`](#string) | Human readable representation for the access level. | | `deployKey` | [`AccessLevelDeployKey`](#accessleveldeploykey) | Deploy key assigned to the access level. | -| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. | -| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. | +| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with the access level. | +| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with the access level. | ### `PushRules` @@ -36883,12 +36885,12 @@ Evidence for a release. | Name | Type | Description | | ---- | ---- | ----------- | -| `closedIssuesUrl` | [`String`](#string) | HTTP URL of the issues page, filtered by this release and `state=closed`. | -| `closedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page , filtered by this release and `state=closed`. | +| `closedIssuesUrl` | [`String`](#string) | HTTP URL of the issues page, filtered by the release and `state=closed`. | +| `closedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page, filtered by the release and `state=closed`. | | `editUrl` | [`String`](#string) | HTTP URL of the release's edit page. | -| `mergedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page , filtered by this release and `state=merged`. | -| `openedIssuesUrl` | [`String`](#string) | HTTP URL of the issues page, filtered by this release and `state=open`. | -| `openedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page, filtered by this release and `state=open`. | +| `mergedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page, filtered by the release and `state=merged`. | +| `openedIssuesUrl` | [`String`](#string) | HTTP URL of the issues page, filtered by the release and `state=open`. | +| `openedMergeRequestsUrl` | [`String`](#string) | HTTP URL of the merge request page, filtered by the release and `state=open`. | | `selfUrl` | [`String`](#string) | HTTP URL of the release. | ### `ReleaseSource` @@ -37039,13 +37041,13 @@ Returns [`RepositoryCodeownerValidation`](#repositorycodeownervalidation). | `externalStorageUrl` | [`String`](#string) | Web path to download the raw blob via external storage, if enabled. | | `fileType` | [`String`](#string) | Expected format of the blob based on the extension. | | `findFilePath` | [`String`](#string) | Web path to find file. | -| `forkAndEditPath` | [`String`](#string) | Web path to edit this blob using a forked project. | -| `forkAndViewPath` | [`String`](#string) | Web path to view this blob using a forked project. | +| `forkAndEditPath` | [`String`](#string) | Web path to edit the blob using a forked project. | +| `forkAndViewPath` | [`String`](#string) | Web path to view the blob using a forked project. | | `gitpodBlobUrl` | [`String`](#string) | URL to the blob within Gitpod. | | `historyPath` | [`String`](#string) | Web path to blob history page. | | `id` | [`ID!`](#id) | ID of the blob. | -| `ideEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE. | -| `ideForkAndEditPath` | [`String`](#string) | Web path to edit this blob in the Web IDE using a forked project. | +| `ideEditPath` | [`String`](#string) | Web path to edit the blob in the Web IDE. | +| `ideForkAndEditPath` | [`String`](#string) | Web path to edit the blob in the Web IDE using a forked project. | | `language` | [`String`](#string) | Blob language. | | `lfsOid` | [`String`](#string) | LFS OID of the blob. | | `mode` | [`String`](#string) | Blob mode. | @@ -37702,11 +37704,11 @@ Represents a snippet entry. | Name | Type | Description | | ---- | ---- | ----------- | | `author` | [`UserCore`](#usercore) | Owner of the snippet. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | -| `createdAt` | [`Time!`](#time) | Timestamp this snippet was created. | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | +| `createdAt` | [`Time!`](#time) | Timestamp the snippet was created. | | `description` | [`String`](#string) | Description of the snippet. | | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `fileName` | [`String`](#string) | File Name of the snippet. | | `hidden` | [`Boolean!`](#boolean) | Indicates the snippet is hidden because the author has been banned. | | `httpUrlToRepo` | [`String`](#string) | HTTP URL to the snippet repository. | @@ -37717,7 +37719,7 @@ Represents a snippet entry. | `rawUrl` | [`String!`](#string) | Raw URL of the snippet. | | `sshUrlToRepo` | [`String`](#string) | SSH URL to the snippet repository. | | `title` | [`String!`](#string) | Title of the snippet. | -| `updatedAt` | [`Time!`](#time) | Timestamp this snippet was updated. | +| `updatedAt` | [`Time!`](#time) | Timestamp the snippet was updated. | | `userPermissions` | [`SnippetPermissions!`](#snippetpermissions) | Permissions for the current user on the resource. | | `visibilityLevel` | [`VisibilityLevelsEnum!`](#visibilitylevelsenum) | Visibility Level of the snippet. | | `webUrl` | [`String!`](#string) | Web URL of the snippet. | @@ -38131,10 +38133,10 @@ Terraform module metadata submodule. | Name | Type | Description | | ---- | ---- | ----------- | | `createdAt` | [`Time!`](#time) | Timestamp the version was created. | -| `createdByUser` | [`UserCore`](#usercore) | User that created this version. | +| `createdByUser` | [`UserCore`](#usercore) | User that created the version. | | `downloadPath` | [`String`](#string) | URL for downloading the version's JSON file. | | `id` | [`ID!`](#id) | ID of the Terraform state version. | -| `job` | [`CiJob`](#cijob) | Job that created this version. | +| `job` | [`CiJob`](#cijob) | Job that created the version. | | `serial` | [`Int`](#int) | Serial number of the version. | | `updatedAt` | [`Time!`](#time) | Timestamp the version was updated. | @@ -38390,15 +38392,15 @@ Representing a to-do entry. | Name | Type | Description | | ---- | ---- | ----------- | | `action` | [`TodoActionEnum!`](#todoactionenum) | Action of the to-do item. | -| `author` | [`UserCore!`](#usercore) | Author of this to-do item. | +| `author` | [`UserCore!`](#usercore) | Author of the to-do item. | | `body` | [`String!`](#string) | Body of the to-do item. | -| `createdAt` | [`Time!`](#time) | Timestamp this to-do item was created. | -| `group` | [`Group`](#group) | Group this to-do item is associated with. | +| `createdAt` | [`Time!`](#time) | Timestamp the to-do item was created. | +| `group` | [`Group`](#group) | Group the to-do item is associated with. | | `id` | [`ID!`](#id) | ID of the to-do item. | | `memberAccessType` | [`String`](#string) | Access type of access request to-do items. | -| `note` | [`Note`](#note) | Note which created this to-do item. | -| `project` | [`Project`](#project) | Project this to-do item is associated with. | -| `snoozedUntil` | [`Time`](#time) | The time until when the todo is snoozed. | +| `note` | [`Note`](#note) | Note which created the to-do item. | +| `project` | [`Project`](#project) | Project the to-do item is associated with. | +| `snoozedUntil` | [`Time`](#time) | Time until when the todo is snoozed. | | `state` | [`TodoStateEnum!`](#todostateenum) | State of the to-do item. | | `target` {{< icon name="warning-solid" >}} | [`Todoable!`](#todoable) | **Deprecated** in GitLab 17.4. Use `target_entity` field. | | `targetEntity` | [`Todoable`](#todoable) | Target of the to-do item. | @@ -38456,8 +38458,8 @@ Defines which user roles, users, or groups can unprotect a protected branch. | ---- | ---- | ----------- | | `accessLevel` | [`Int!`](#int) | GitLab::Access level. | | `accessLevelDescription` | [`String!`](#string) | Human readable representation for the access level. | -| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. | -| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. | +| `group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with the access level. | +| `user` | [`AccessLevelUser`](#accessleveluser) | User associated with the access level. | ### `UploadRegistry` @@ -38580,7 +38582,7 @@ Core representation of a GitLab user. | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | @@ -38974,11 +38976,11 @@ fields relate to interactions between the two entities. | Name | Type | Description | | ---- | ---- | ----------- | | `applicableApprovalRules` | [`[ApprovalRule!]`](#approvalrule) | Approval rules that apply to this user for this merge request. | -| `approved` | [`Boolean!`](#boolean) | Whether this user has approved this merge request. | -| `canMerge` | [`Boolean!`](#boolean) | Whether this user can merge this merge request. | -| `canUpdate` | [`Boolean!`](#boolean) | Whether this user can update this merge request. | -| `reviewState` | [`MergeRequestReviewState`](#mergerequestreviewstate) | State of the review by this user. | -| `reviewed` | [`Boolean!`](#boolean) | Whether this user has provided a review for this merge request. | +| `approved` | [`Boolean!`](#boolean) | Whether the user has approved the merge request. | +| `canMerge` | [`Boolean!`](#boolean) | Whether the user can merge the merge request. | +| `canUpdate` | [`Boolean!`](#boolean) | Whether the user can update the merge request. | +| `reviewState` | [`MergeRequestReviewState`](#mergerequestreviewstate) | State of the review by the user. | +| `reviewed` | [`Boolean!`](#boolean) | Whether the user has provided a review for the merge request. | ### `UserPermissions` @@ -39226,7 +39228,7 @@ Represents a vulnerability. | ---- | ---- | ----------- | | `aiResolutionAvailable` | [`Boolean`](#boolean) | Indicates whether this type of vulnerability can be resolved with AI. | | `aiResolutionEnabled` | [`Boolean`](#boolean) | Indicates whether this specific vulnerability can be resolved with AI. | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | | `confirmedAt` | [`Time`](#time) | Timestamp of when the vulnerability state was changed to confirmed. | | `confirmedBy` | [`UserCore`](#usercore) | User that confirmed the vulnerability. | | `cveEnrichment` | [`CveEnrichmentType`](#cveenrichmenttype) | Enrichment (EPSS score and KEV) for CVE vulnerabilities. | @@ -39235,7 +39237,7 @@ Represents a vulnerability. | `descriptionHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `description`. | | `details` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Details of the vulnerability. | | `detectedAt` | [`Time!`](#time) | Timestamp of when the vulnerability was first detected. | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason for dismissal. Returns `null` for states other than `dismissed`. | | `dismissedAt` | [`Time`](#time) | Timestamp of when the vulnerability state was changed to dismissed. | | `dismissedBy` | [`UserCore`](#usercore) | User that dismissed the vulnerability. | @@ -39247,7 +39249,7 @@ Represents a vulnerability. | `links` | [`[VulnerabilityLink!]!`](#vulnerabilitylink) | List of links associated with the vulnerability. | | `location` | [`VulnerabilityLocation`](#vulnerabilitylocation) | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability. | | `mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request that fixes the vulnerability. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `presentOnDefaultBranch` | [`Boolean!`](#boolean) | Indicates whether the vulnerability is present on the default branch or not. | | `primaryIdentifier` | [`VulnerabilityIdentifier`](#vulnerabilityidentifier) | Primary identifier of the vulnerability. | | `project` | [`Project`](#project) | Project on which the vulnerability was found. | @@ -39958,13 +39960,13 @@ A wiki page. | Name | Type | Description | | ---- | ---- | ----------- | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | | `id` | [`WikiPageMetaID!`](#wikipagemetaid) | Global ID of the wiki page metadata record. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `title` | [`String!`](#string) | Wiki page title. | | `userPermissions` | [`WikiPagePermissions!`](#wikipagepermissions) | Permissions for the current user on the resource. | -| `webUrl` | [`String`](#string) | URL of this object. | +| `webUrl` | [`String`](#string) | URL of the object. | #### Fields with arguments @@ -40012,7 +40014,7 @@ four standard [pagination arguments](#pagination-arguments): | `iid` | [`String!`](#string) | Internal ID of the work item. | | `lockVersion` | [`Int!`](#int) | Lock version of the work item. Incremented each time the work item is updated. | | `movedToWorkItemUrl` | [`String`](#string) | URL of the work item that the work item was moved to. | -| `name` | [`String`](#string) | Name or title of this object. | +| `name` | [`String`](#string) | Name or title of the object. | | `namespace` {{< icon name="warning-solid" >}} | [`Namespace`](#namespace) | **Introduced** in GitLab 15.10. **Status**: Experiment. Namespace the work item belongs to. | | `project` {{< icon name="warning-solid" >}} | [`Project`](#project) | **Introduced** in GitLab 15.3. **Status**: Experiment. Project the work item belongs to. | | `promotedToEpicUrl` | [`String`](#string) | URL of the epic that the work item has been promoted to. | @@ -40022,7 +40024,7 @@ four standard [pagination arguments](#pagination-arguments): | `updatedAt` | [`Time!`](#time) | Timestamp of when the work item was last updated. | | `userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the work item. | | `userPermissions` | [`WorkItemPermissions!`](#workitempermissions) | Permissions for the current user on the resource. | -| `webUrl` | [`String`](#string) | URL of this object. | +| `webUrl` | [`String`](#string) | URL of the object. | | `workItemType` | [`WorkItemType!`](#workitemtype) | Type assigned to the work item. | #### Fields with arguments @@ -40955,6 +40957,7 @@ The category of the additional context. | `LOCAL_GIT` | Local_git content category. | | `MERGE_REQUEST` | Merge_request content category. | | `SNIPPET` | Snippet content category. | +| `TERMINAL` | Terminal content category. | ### `AiConversationsThreadsConversationType` @@ -46418,8 +46421,8 @@ Implementations: | Name | Type | Description | | ---- | ---- | ----------- | -| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on this noteable. (see [Connections](#connections)) | -| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) | +| `commenters` | [`UserCoreConnection!`](#usercoreconnection) | All commenters on the noteable. (see [Connections](#connections)) | +| `discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on the noteable. (see [Connections](#connections)) | ##### Fields with arguments @@ -46639,8 +46642,8 @@ Implementations: | Name | Type | Description | | ---- | ---- | ----------- | -| `name` | [`String`](#string) | Name or title of this object. | -| `webUrl` | [`String`](#string) | URL of this object. | +| `name` | [`String`](#string) | Name or title of the object. | +| `webUrl` | [`String`](#string) | URL of the object. | #### `User` @@ -46697,7 +46700,7 @@ Implementations: | `type` | [`UserType!`](#usertype) | Type of the user. | | `userPermissions` | [`UserPermissions!`](#userpermissions) | Permissions for the current user on the resource. | | `userPreferences` | [`UserPreferences`](#userpreferences) | Preferences for the user. | -| `username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. | +| `username` | [`String!`](#string) | Username of the user. Unique within the instance of GitLab. | | `webPath` | [`String!`](#string) | Web path of the user. | | `webUrl` | [`String!`](#string) | Web URL of the user. | diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index 38df2a04f2a..51557f90364 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -167,9 +167,10 @@ Predefined variables become available at three different phases of pipeline exec ## Predefined variables for merge request pipelines -These variables are available before GitLab creates the pipeline (Pre-pipeline). -These variables can be used with `include:rules` to control which configuration files -to use when creating the pipeline. +These variables are available before GitLab creates the pipeline +(Pre-pipeline). These variables can be used with +[`include:rules`](../../ci/yaml/includes.md#use-rules-with-include) +and as environment variables in jobs. The pipeline must be a [merge request pipeline](../pipelines/merge_request_pipelines.md), and the merge request must be open. @@ -177,16 +178,16 @@ and the merge request must be open. | Variable | Description | |---------------------------------------------|-------------| | `CI_MERGE_REQUEST_APPROVED` | Approval status of the merge request. `true` when [merge request approvals](../../user/project/merge_requests/approvals/_index.md) is available and the merge request has been approved. | -| `CI_MERGE_REQUEST_ASSIGNEES` | Comma-separated list of usernames of assignees for the merge request. | +| `CI_MERGE_REQUEST_ASSIGNEES` | Comma-separated list of usernames of assignees for the merge request. Only available if the merge request has at least one assignee. | | `CI_MERGE_REQUEST_DIFF_BASE_SHA` | The base SHA of the merge request diff. | | `CI_MERGE_REQUEST_DIFF_ID` | The version of the merge request diff. | | `CI_MERGE_REQUEST_EVENT_TYPE` | The event type of the merge request. Can be `detached`, `merged_result` or `merge_train`. | | `CI_MERGE_REQUEST_DESCRIPTION` | The description of the merge request. If the description is more than 2700 characters long, only the first 2700 characters are stored in the variable. Introduced in GitLab 16.7. | -| `CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED` | `true` if `CI_MERGE_REQUEST_DESCRIPTION` is truncated down to 2700 characters because the description of the merge request is too long. Introduced in GitLab 16.8. | +| `CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED` | `true` if `CI_MERGE_REQUEST_DESCRIPTION` is truncated down to 2700 characters because the description of the merge request is too long, otherwise `false`. Introduced in GitLab 16.8. | | `CI_MERGE_REQUEST_ID` | The instance-level ID of the merge request. The ID is unique across all projects on the GitLab instance. | | `CI_MERGE_REQUEST_IID` | The project-level IID (internal ID) of the merge request. This ID is unique for the current project, and is the number used in the merge request URL, page title, and other visible locations. | -| `CI_MERGE_REQUEST_LABELS` | Comma-separated label names of the merge request. | -| `CI_MERGE_REQUEST_MILESTONE` | The milestone title of the merge request. | +| `CI_MERGE_REQUEST_LABELS` | Comma-separated label names of the merge request. Only available if the merge request has at least one label. | +| `CI_MERGE_REQUEST_MILESTONE` | The milestone title of the merge request. Only available if the merge request has a milestone set. | | `CI_MERGE_REQUEST_PROJECT_ID` | The ID of the project of the merge request. | | `CI_MERGE_REQUEST_PROJECT_PATH` | The path of the project of the merge request. For example `namespace/awesome-project`. | | `CI_MERGE_REQUEST_PROJECT_URL` | The URL of the project of the merge request. For example, `http://192.168.10.15:3000/namespace/awesome-project`. | diff --git a/doc/development/advanced_search.md b/doc/development/advanced_search.md index b66768124af..de74e07bfba 100644 --- a/doc/development/advanced_search.md +++ b/doc/development/advanced_search.md @@ -1004,14 +1004,20 @@ Requires `source_branch` field. Query with `source_branch` or `not_source_branch } ``` -##### `by_group_level_authorization` +##### `by_search_level_and_group_membership` Requires `current_user`, `group_ids`, `traversal_id`, `search_level` fields. Query with `search_level` and -filter on `namespace_visibility_level` based on permissions user has for each group. +filter on `namespace_visibility_level` based on permissions user has for each group. {{< alert type="note" >}} -Examples are shown for a logged in user. The JSON may be different for users with authorizations, admins, external, or anonymous users +This filter can be used in place of `by_search_level_and_membership` if the data being searched does not contain the `project_id` field. + +{{< /alert >}} + +{{< alert type="note" >}} + +Examples are shown for an authenticated user. The JSON may be different for users with authorizations, admins, external, or anonymous users {{< /alert >}} diff --git a/doc/development/cloud_connector/configuration.md b/doc/development/cloud_connector/configuration.md index 1c005f27774..f51446a922d 100644 --- a/doc/development/cloud_connector/configuration.md +++ b/doc/development/cloud_connector/configuration.md @@ -176,6 +176,7 @@ unit_primitives: - include_local_git_context - include_merge_request_context - include_snippet_context + - include_terminal_context - refactor_code - write_tests ``` diff --git a/doc/security/hardening_cicd_recommendations.md b/doc/security/hardening_cicd_recommendations.md index a668eb9afc5..f2e7faa0e56 100644 --- a/doc/security/hardening_cicd_recommendations.md +++ b/doc/security/hardening_cicd_recommendations.md @@ -7,7 +7,7 @@ title: Hardening - CI/CD Recommendations General hardening guidelines and philosophies are outlined in the [main hardening documentation](hardening.md). -The hardening recommendations and concepts for CI/CD are listed below. +The hardening recommendations and concepts for CI/CD are discussed below. ## Basic Recommendations @@ -20,32 +20,17 @@ potentially sensitive information to be used during CI/CD operations. As the individual scenarios themselves are numerous, we have summarized some basic information to help harden the CI/CD process. -- **Secrets Management**. Passwords, tokens, keys, and other secrets that require any - level of protection should never be stored in plaintext. Some type of encrypted - container technology should be used, such as GCP Secret Manager, AWS KMS, or - HashiCorp Vault. For self-managed and standalone instances, HashiCorp Vault is - recommended, and many GitLab features can take advantage of Vault and are well - documented in the main [Documentation](../_index.md). For detailed CI/CD examples, see [using external secrets in CI](../ci/secrets/_index.md). -- **External Communications**. If your CI/CD process requires connectivity to other - hosts, ensure that these communication channels are encrypted. You should use TLS 1.2 or 1.3, and where possible implement mutual TLS. -- **Logging**. Logging can be very important for auditing and troubleshooting, so it - is important that you enable any logging features to ensure you are getting - the information in logs you need. Make sure through periodic testing that - plaintext secrets or other sensitive information is not inadvertently added to log - files. +The general guidance is to: + +- Protect secrets. +- Ensure network communications are encrypted. +- Use thorough logging for auditing and troubleshooting purposes. ## Specific Recommendations -### Pipelines - -Pipelines are a part of jobs that execute steps in stages to automate tasks on behalf -of the users of a project. They are a core component of CD/CD. - -By default, only the default branch gets a protected pipeline. An owner of a project -can ensure that other branches are protected by -[configuring a protected branch](../user/project/repository/branches/protected.md). -This allows for more restricted security on pipelines. For more information, see -[pipeline security on a protected branch](../ci/pipelines/_index.md#pipeline-security-on-protected-branches). +Pipelines are a core component of GitLab CI/CD that execute jobs in stages to automate tasks +on behalf of the users of a project. For specific guidelines on dealing with pipelines, +see the information on [pipeline security](../ci/pipelines/pipeline_security.md). Deployment is the part of the CI/CD that deploys the results of the pipeline in relationship to a given environment. Default settings do not impose many diff --git a/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml index 9838ce62cb1..eda68caf551 100644 --- a/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml @@ -152,7 +152,7 @@ gitlab-enrich-cdx-results: stage: .post extends: .static-reachability-rules variables: - GLAS_STATIC_REACHABILITY_MATCHER_VERSION: "v1.0.1" + GLAS_STATIC_REACHABILITY_MATCHER_VERSION: "v1.0.3" GLAS_REPORT: $GITLAB_ADVANCED_SAST_SCA_FILENAME SCA_TO_SARIF_PROJECT_ID: 60962090 DEPENDENCY_SCANNING_PATTERN: "**/gl-sbom-*-*.cdx.json" diff --git a/lib/gitlab/redis.rb b/lib/gitlab/redis.rb index dd66d1d51c7..cfd2ada7b2e 100644 --- a/lib/gitlab/redis.rb +++ b/lib/gitlab/redis.rb @@ -10,7 +10,6 @@ module Gitlab ALL_CLASSES = [ Gitlab::Redis::BufferedCounter, Gitlab::Redis::Cache, - Gitlab::Redis::ClusterSessions, Gitlab::Redis::DbLoadBalancing, Gitlab::Redis::FeatureFlag, *Gitlab::Redis::Queues.instances.values, # dynamically adds QueueShard* classes diff --git a/lib/gitlab/redis/cluster_sessions.rb b/lib/gitlab/redis/cluster_sessions.rb deleted file mode 100644 index caaad3c29ad..00000000000 --- a/lib/gitlab/redis/cluster_sessions.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Redis - class ClusterSessions < ::Gitlab::Redis::Wrapper - class << self - # The data we store on Sessions used to be stored on SharedState. - def config_fallback - SharedState - end - end - end - end -end diff --git a/lib/gitlab/redis/sessions.rb b/lib/gitlab/redis/sessions.rb index 093f896dbd3..ddcfdf6e798 100644 --- a/lib/gitlab/redis/sessions.rb +++ b/lib/gitlab/redis/sessions.rb @@ -2,7 +2,7 @@ module Gitlab module Redis - class Sessions < ::Gitlab::Redis::MultiStoreWrapper + class Sessions < ::Gitlab::Redis::Wrapper SESSION_NAMESPACE = 'session:gitlab' USER_SESSIONS_NAMESPACE = 'session:user:gitlab' USER_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:user:gitlab' @@ -13,10 +13,6 @@ module Gitlab def self.config_fallback SharedState end - - def self.multistore - MultiStore.create_using_pool(ClusterSessions.pool, pool, store_name) - end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b358a190614..45c1263bd52 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -29498,9 +29498,6 @@ msgstr "" msgid "Hide details" msgstr "" -msgid "Hide empty" -msgstr "" - msgid "Hide file browser" msgstr "" @@ -38663,9 +38660,6 @@ msgstr "" msgid "No AI gateway available." msgstr "" -msgid "No Author" -msgstr "" - msgid "No Epic" msgstr "" @@ -38825,9 +38819,6 @@ msgstr "" msgid "No issues found" msgstr "" -msgid "No items" -msgstr "" - msgid "No iteration" msgstr "" @@ -55465,9 +55456,6 @@ msgstr "" msgid "Show details" msgstr "" -msgid "Show empty" -msgstr "" - msgid "Show file browser" msgstr "" @@ -56015,9 +56003,15 @@ msgstr "" msgid "Snippets|Files" msgstr "" +msgid "Snippets|New snippet" +msgstr "" + msgid "Snippets|Snippet actions" msgstr "" +msgid "Snippets|Snippets" +msgstr "" + msgid "Snippets|Snippets are limited to %{total} files." msgstr "" @@ -66421,9 +66415,21 @@ msgstr "" msgid "WorkItem|Are you sure you want to delete the %{workItemType}? This action cannot be reversed." msgstr "" +msgid "WorkItem|Assignee" +msgstr "" + msgid "WorkItem|Assignees" msgstr "" +msgid "WorkItem|At risk" +msgstr "" + +msgid "WorkItem|Author" +msgstr "" + +msgid "WorkItem|Back" +msgstr "" + msgid "WorkItem|Blocked by" msgstr "" @@ -66607,9 +66613,18 @@ msgstr "" msgid "WorkItem|Forest green" msgstr "" +msgid "WorkItem|Group by" +msgstr "" + +msgid "WorkItem|Health Status" +msgstr "" + msgid "WorkItem|Health status" msgstr "" +msgid "WorkItem|Hide empty" +msgstr "" + msgid "WorkItem|History only" msgstr "" @@ -66637,6 +66652,9 @@ msgstr "" msgid "WorkItem|Key result" msgstr "" +msgid "WorkItem|Label" +msgstr "" + msgid "WorkItem|Labels" msgstr "" @@ -66691,6 +66709,9 @@ msgstr "" msgid "WorkItem|Must be a valid hex code" msgstr "" +msgid "WorkItem|Needs attention" +msgstr "" + msgid "WorkItem|New" msgstr "" @@ -66724,6 +66745,9 @@ msgstr "" msgid "WorkItem|No child items are currently open." msgstr "" +msgid "WorkItem|No items" +msgstr "" + msgid "WorkItem|No iteration" msgstr "" @@ -66760,6 +66784,9 @@ msgstr "" msgid "WorkItem|Objective" msgstr "" +msgid "WorkItem|On track" +msgstr "" + msgid "WorkItem|One or more items cannot be shown. If you're using SAML authentication, this could mean your session has expired." msgstr "" @@ -66850,6 +66877,9 @@ msgstr "" msgid "WorkItem|Show closed items" msgstr "" +msgid "WorkItem|Show empty" +msgstr "" + msgid "WorkItem|Show labels" msgstr "" diff --git a/patches/vue-test-utils-compat+0.0.14.patch b/patches/vue-test-utils-compat+0.0.14.patch new file mode 100644 index 00000000000..393c0846a8a --- /dev/null +++ b/patches/vue-test-utils-compat+0.0.14.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/vue-test-utils-compat/dist/vue-test-utils-compat.cjs.js b/node_modules/vue-test-utils-compat/dist/vue-test-utils-compat.cjs.js +index 65fccb5..5a698da 100644 +--- a/node_modules/vue-test-utils-compat/dist/vue-test-utils-compat.cjs.js ++++ b/node_modules/vue-test-utils-compat/dist/vue-test-utils-compat.cjs.js +@@ -281,8 +281,16 @@ function normalizeScopedSlots(scopedSlots, scopedSlotsThis) { + return Object.fromEntries( + Object.entries(scopedSlots).map(([k, v]) => { + let normalizedValue = v; +- if (typeof v === "string" && !v.startsWith("${v}`; ++ if (typeof v === "string") { ++ // TODO: Remove this patch once ++ // https://gitlab.com/xanf/vue-test-utils-compat/-/merge_requests/8 ++ // is merged and released. ++ if (v.trim().startsWith("${v}`; ++ } + } else if (typeof v === "function") { + normalizedValue = (...args) => v.call(scopedSlotsThis, ...args); + } else { diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_spec.rb index 7ce68bd5e90..8754b802377 100644 --- a/qa/qa/specs/features/api/3_create/merge_request/push_options_spec.rb +++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_spec.rb @@ -7,13 +7,17 @@ module QA # # git config --global receive.advertisepushoptions true + let(:project) { create(:project, :with_readme) } let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" } - let(:target_branch) { create(:branch, name: "push-options-test-target-#{SecureRandom.hex(8)}", project: project) } let(:title) { "MR push options test #{SecureRandom.hex(8)}" } let(:commit_message) { 'Add README.md' } - let(:project) { create(:project, :with_readme) } let(:description) { "This is a test of MR push options" } + let(:target_branch) do + create(:branch, name: "push-options-test-target-#{SecureRandom.hex(8)}", project: project, + ref: project.default_branch) + end + before do Resource::Repository::ProjectPush.fabricate! do |push| push.project = project diff --git a/rubocop/cop/.rubocop.yml b/rubocop/cop/.rubocop.yml new file mode 100644 index 00000000000..47061356f05 --- /dev/null +++ b/rubocop/cop/.rubocop.yml @@ -0,0 +1,3 @@ +--- +inherit_from: + - '../../.rubocop/internal_affairs.yml' diff --git a/scripts/frontend/quarantined_vue3_specs.txt b/scripts/frontend/quarantined_vue3_specs.txt index a32b468c0bc..fde20413787 100644 --- a/scripts/frontend/quarantined_vue3_specs.txt +++ b/scripts/frontend/quarantined_vue3_specs.txt @@ -31,7 +31,6 @@ ee/spec/frontend/dependencies/components/app_spec.js ee/spec/frontend/dependencies/components/dependency_location_spec.js ee/spec/frontend/dependencies/components/dependency_path_viewer_spec.js ee/spec/frontend/dependencies/components/filtered_search/tokens/component_token_spec.js -ee/spec/frontend/geo_sites/components/details/secondary_site/geo_site_replication_details_responsive_spec.js ee/spec/frontend/geo_sites/index_spec.js ee/spec/frontend/groups/settings/components/comma_separated_list_token_selector_spec.js ee/spec/frontend/integrations/edit/components/jira_issue_creation_vulnerabilities_spec.js @@ -67,7 +66,6 @@ ee/spec/frontend/roles_and_permissions/components/role_selector_spec.js ee/spec/frontend/security_configuration/components/app_spec.js ee/spec/frontend/security_configuration/components/dynamic_fields_spec.js ee/spec/frontend/security_configuration/dast_profiles/components/dast_profiles_list_spec.js -ee/spec/frontend/security_configuration/dast_profiles/dast_profile_selector/site_profile_selector_spec.js ee/spec/frontend/security_dashboard/components/shared/filters/querystring_sync_spec.js ee/spec/frontend/security_dashboard/components/shared/vulnerability_details_graphql/details_section_spec.js ee/spec/frontend/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql_spec.js @@ -229,7 +227,6 @@ spec/frontend/vue_shared/components/file_tree_spec.js spec/frontend/vue_shared/components/filtered_search_bar/tokens/date_token_spec.js spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js spec/frontend/vue_shared/components/metric_images/metric_image_details_modal_spec.js -spec/frontend/vue_shared/components/page_heading_spec.js spec/frontend/vue_shared/components/pagination_bar/pagination_bar_spec.js spec/frontend/vue_shared/components/project_selector/project_selector_spec.js spec/frontend/vue_shared/components/registry/code_instruction_spec.js diff --git a/scripts/undercoverage b/scripts/undercoverage index 0a6dd615090..f831d6e0d45 100755 --- a/scripts/undercoverage +++ b/scripts/undercoverage @@ -26,9 +26,17 @@ coverage_file_path = 'coverage/lcov/gitlab.lcov' # By default undercover includes Ruby related files and only excludes common paths # like test, spec, *_spec.rb exclude_file_globs = Undercover::Options::DEFAULT_FILE_EXCLUDE_GLOBS.dup + # We need to exclude more folders: -exclude_file_globs.concat %w[ee/spec/* jh/spec/*] # These are specs too -exclude_file_globs.concat %w[qa/* gems/* vendor/*] # These have own specs +# EE/JH counterparts for default globs +extension_globs = Undercover::Options::DEFAULT_FILE_EXCLUDE_GLOBS.flat_map do |glob| + %W[jh/#{glob} ee/#{glob}] unless glob.start_with?('*') +end.compact + +exclude_file_globs.concat extension_globs + +# These have own specs +exclude_file_globs.concat %w[qa/* gems/* vendor/*] result = if File.exist?(coverage_file_path) Undercover::CLI.run(%W[-c #{compare_base} --exclude-files #{exclude_file_globs.join(',')}]) diff --git a/spec/components/previews/layouts/crud_component_preview.rb b/spec/components/previews/layouts/crud_component_preview.rb index 73ad8e017da..b87b92dee80 100644 --- a/spec/components/previews/layouts/crud_component_preview.rb +++ b/spec/components/previews/layouts/crud_component_preview.rb @@ -7,6 +7,7 @@ module Layouts # @param count number # @param icon text # @param toggle_text text + # @param is_collapsible # rubocop:disable Metrics/ParameterLists -- allow all params def default( title: 'CRUD Component title', @@ -19,7 +20,8 @@ module Layouts body: 'Body slot', form: 'Form slot', footer: 'Footer slot', - pagination: 'Pagination slot' + pagination: 'Pagination slot', + is_collapsible: false ) render(::Layouts::CrudComponent.new( title, @@ -27,7 +29,8 @@ module Layouts count: count, icon: icon, icon_class: icon_class, - toggle_text: toggle_text)) do |c| + toggle_text: toggle_text, + is_collapsible: is_collapsible)) do |c| c.with_description { description } c.with_actions { actions } c.with_body { body } diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb index 71e1bcaa45a..1da2b53da36 100644 --- a/spec/db/schema_spec.rb +++ b/spec/db/schema_spec.rb @@ -16,10 +16,8 @@ RSpec.describe 'Database schema', let(:ignored_indexes_on_fks_map) do { - ai_testing_terms_acceptances: %w[user_id], # testing terms only have 1 entry, and if the user is deleted the record should remain ci_build_trace_metadata: [%w[partition_id build_id], %w[partition_id trace_artifact_id]], # the index on build_id is enough ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081 - ci_build_needs: %w[project_id], # we will create async index, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163429#note_2065627176 ci_daily_build_group_report_results: [%w[partition_id last_pipeline_id]], # index on last_pipeline_id is sufficient ci_pipeline_artifacts: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_pipeline_chat_data: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient @@ -31,7 +29,6 @@ RSpec.describe 'Database schema', ci_sources_pipelines: [%w[source_partition_id source_pipeline_id], %w[partition_id pipeline_id]], ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient - notes: %w[namespace_id], # this index is added in an async manner, hence it needs to be ignored in the first phase. p_ci_build_trace_metadata: [%w[partition_id build_id], %w[partition_id trace_artifact_id]], # the index on build_id is enough p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081 p_ci_builds_execution_configs: [%w[partition_id pipeline_id]], # the index on pipeline_id is enough @@ -39,7 +36,6 @@ RSpec.describe 'Database schema', p_ci_pipeline_variables: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient p_ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient slack_integrations_scopes: [%w[slack_api_scope_id]], - snippets: %w[organization_id], # this index is added in an async manner, hence it needs to be ignored in the first phase. users: [%w[accepted_term_id]], subscription_add_on_purchases: [["subscription_add_on_id"]] # index handled via composite index with namespace_id }.with_indifferent_access.freeze @@ -178,7 +174,7 @@ RSpec.describe 'Database schema', merge_request_diff_commits_b5377a7a34: %w[merge_request_diff_id commit_author_id committer_id project_id], namespaces: %w[owner_id parent_id], namespace_descendants: %w[namespace_id], - notes: %w[author_id commit_id noteable_id updated_by_id resolved_by_id confirmed_by_id discussion_id namespace_id], + notes: %w[author_id commit_id noteable_id updated_by_id resolved_by_id confirmed_by_id discussion_id], notification_settings: %w[source_id], oauth_access_grants: %w[resource_owner_id application_id], oauth_access_tokens: %w[resource_owner_id application_id], diff --git a/spec/finders/work_items/work_items_finder_spec.rb b/spec/finders/work_items/work_items_finder_spec.rb index 8151317a9d9..43d63918165 100644 --- a/spec/finders/work_items/work_items_finder_spec.rb +++ b/spec/finders/work_items/work_items_finder_spec.rb @@ -149,4 +149,75 @@ RSpec.describe WorkItems::WorkItemsFinder, feature_category: :team_planning do end end end + + context 'with start and end date filtering' do + include_context '{Issues|WorkItems}Finder#execute context', :work_item + + let(:scope) { 'all' } + let(:params) { { start_date: '2020-08-12', end_date: '2020-08-14', group_id: group.id } } + + context 'when namespace level work items are disabled' do + before do + stub_feature_flags(namespace_level_work_items: false) + group.add_developer(user) + end + + let_it_be(:work_item1) { create(:work_item, project: project1) } + let_it_be(:work_item2) { create(:work_item, project: project1) } + + let_it_be(:date_source1) do + create(:work_items_dates_source, work_item: work_item1, start_date: '2020-08-13', due_date: '2020-08-15') + end + + let_it_be(:date_source2) do + create(:work_items_dates_source, work_item: work_item2, start_date: '2020-08-16', due_date: '2020-08-20') + end + + it 'does not attempt to filter by timeframe' do + expect(items).to include(work_item1, work_item2) + end + end + + context 'when namespace level work items are enabled' do + before do + stub_feature_flags(namespace_level_work_items: true, work_item_epics: true) + group.add_developer(user) + end + + let_it_be(:work_item1) { create(:work_item, :group_level, :epic, namespace: group) } + let_it_be(:work_item2) { create(:work_item, :group_level, :epic, namespace: group) } + + it 'does not return work items without a dates source' do + expect(items).to be_empty + end + + context 'when work item start and due dates are both present' do + let_it_be(:date_source1) do + create(:work_items_dates_source, work_item: work_item1, start_date: '2020-08-13', due_date: '2020-08-15') + end + + let_it_be(:date_source2) do + create(:work_items_dates_source, work_item: work_item2, start_date: '2020-08-16', due_date: '2020-08-20') + end + + it 'returns only work items within timeframe' do + expect(items).to contain_exactly(work_item1) + end + end + + context 'when only start date or due date is present' do + let_it_be(:date_source_only_start) do + create(:work_items_dates_source, work_item: work_item1, start_date: '2020-08-12', due_date: nil) + end + + let_it_be(:date_source_only_due) do + create(:work_items_dates_source, work_item: work_item2, start_date: nil, due_date: '2020-08-14') + end + + it 'returns only work items within timeframe' do + expect(items).to contain_exactly(work_item1, work_item2) + end + end + end + end end diff --git a/spec/frontend/lib/utils/local_storage_spec.js b/spec/frontend/lib/utils/local_storage_spec.js new file mode 100644 index 00000000000..fbc509996d2 --- /dev/null +++ b/spec/frontend/lib/utils/local_storage_spec.js @@ -0,0 +1,146 @@ +import { getStorageValue, saveStorageValue, removeStorageValue } from '~/lib/utils/local_storage'; + +describe('Local Storage Utils', () => { + const TEST_KEY = 'test_storage_key'; + const STRING_VALUE = 'test string value'; + const OBJECT_VALUE = { name: 'test object', count: 42 }; + const ARRAY_VALUE = [1, 2, 'three', { four: 4 }]; + const NUMBER_VALUE = 123.45; + let spy; + + beforeEach(() => { + // Clear localStorage before each test + localStorage.clear(); + // Spy on console.warn to test warning messages + spy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + describe('saveStorageValue', () => { + it('saves string values correctly', () => { + saveStorageValue(TEST_KEY, STRING_VALUE); + expect(localStorage.getItem(TEST_KEY)).toBe(JSON.stringify(STRING_VALUE)); + }); + + it('saves object values correctly', () => { + saveStorageValue(TEST_KEY, OBJECT_VALUE); + expect(localStorage.getItem(TEST_KEY)).toBe(JSON.stringify(OBJECT_VALUE)); + }); + + it('saves array values correctly', () => { + saveStorageValue(TEST_KEY, ARRAY_VALUE); + expect(localStorage.getItem(TEST_KEY)).toBe(JSON.stringify(ARRAY_VALUE)); + }); + + it('saves number values correctly', () => { + saveStorageValue(TEST_KEY, NUMBER_VALUE); + expect(localStorage.getItem(TEST_KEY)).toBe(JSON.stringify(NUMBER_VALUE)); + }); + + it('saves string values in legacy mode (asString=true)', () => { + saveStorageValue(TEST_KEY, STRING_VALUE, true); + expect(localStorage.getItem(TEST_KEY)).toBe(STRING_VALUE); + }); + + it('warns when saving non-string values with asString=true', () => { + saveStorageValue(TEST_KEY, OBJECT_VALUE, true); + expect(spy).toHaveBeenCalled(); + expect(localStorage.getItem(TEST_KEY)).toBe('[object Object]'); + }); + }); + + describe('getStorageValue', () => { + it('returns { exists: false } when key does not exist', () => { + const result = getStorageValue('nonexistent_key'); + expect(result).toEqual({ exists: false }); + }); + + it('retrieves string values correctly', () => { + localStorage.setItem(TEST_KEY, JSON.stringify(STRING_VALUE)); + const result = getStorageValue(TEST_KEY); + expect(result).toEqual({ exists: true, value: STRING_VALUE }); + }); + + it('retrieves object values correctly', () => { + localStorage.setItem(TEST_KEY, JSON.stringify(OBJECT_VALUE)); + const result = getStorageValue(TEST_KEY); + expect(result).toEqual({ exists: true, value: OBJECT_VALUE }); + }); + + it('retrieves array values correctly', () => { + localStorage.setItem(TEST_KEY, JSON.stringify(ARRAY_VALUE)); + const result = getStorageValue(TEST_KEY); + expect(result).toEqual({ exists: true, value: ARRAY_VALUE }); + }); + + it('retrieves number values correctly', () => { + localStorage.setItem(TEST_KEY, JSON.stringify(NUMBER_VALUE)); + const result = getStorageValue(TEST_KEY); + expect(result).toEqual({ exists: true, value: NUMBER_VALUE }); + }); + + it('retrieves string values in legacy mode (asString=true)', () => { + localStorage.setItem(TEST_KEY, STRING_VALUE); + const result = getStorageValue(TEST_KEY, true); + expect(result).toEqual({ exists: true, value: STRING_VALUE }); + }); + + it('handles JSON parse errors gracefully', () => { + localStorage.setItem(TEST_KEY, '{invalid json}'); + const result = getStorageValue(TEST_KEY); + expect(result).toEqual({ exists: false }); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('removeStorageValue', () => { + it('removes the specified key from localStorage', () => { + // Setup + localStorage.setItem(TEST_KEY, 'some value'); + expect(localStorage.getItem(TEST_KEY)).not.toBeNull(); + + // Test + removeStorageValue(TEST_KEY); + + // Verify + expect(localStorage.getItem(TEST_KEY)).toBeNull(); + }); + + it('does not affect other keys when removing a specific key', () => { + // Setup + const OTHER_KEY = 'other_key'; + localStorage.setItem(TEST_KEY, 'test value'); + localStorage.setItem(OTHER_KEY, 'other value'); + + // Test + removeStorageValue(TEST_KEY); + + // Verify + expect(localStorage.getItem(TEST_KEY)).toBeNull(); + expect(localStorage.getItem(OTHER_KEY)).toBe('other value'); + }); + }); + + describe('integration tests', () => { + it('can save and retrieve values in a round trip', () => { + saveStorageValue(TEST_KEY, OBJECT_VALUE); + const result = getStorageValue(TEST_KEY); + expect(result.exists).toBe(true); + expect(result.value).toEqual(OBJECT_VALUE); + }); + + it('can save and retrieve string values in legacy mode', () => { + saveStorageValue(TEST_KEY, STRING_VALUE, true); + const result = getStorageValue(TEST_KEY, true); + expect(result.exists).toBe(true); + expect(result.value).toBe(STRING_VALUE); + }); + + it('can save, remove, and verify non-existence of values', () => { + saveStorageValue(TEST_KEY, OBJECT_VALUE); + expect(getStorageValue(TEST_KEY).exists).toBe(true); + + removeStorageValue(TEST_KEY); + expect(getStorageValue(TEST_KEY).exists).toBe(false); + }); + }); +}); diff --git a/spec/frontend/rapid_diffs/app/app_spec.js b/spec/frontend/rapid_diffs/app/app_spec.js index c689fec2202..75b65fe2a68 100644 --- a/spec/frontend/rapid_diffs/app/app_spec.js +++ b/spec/frontend/rapid_diffs/app/app_spec.js @@ -6,12 +6,14 @@ import { DiffFile } from '~/rapid_diffs/diff_file'; import { DiffFileMounted } from '~/rapid_diffs/diff_file_mounted'; import { useDiffsList } from '~/rapid_diffs/stores/diffs_list'; import { pinia } from '~/pinia/instance'; +import { initHiddenFilesWarning } from '~/rapid_diffs/app/init_hidden_files_warning'; import { initFileBrowser } from '~/rapid_diffs/app/init_file_browser'; import { StreamingError } from '~/rapid_diffs/streaming_error'; import { useDiffsView } from '~/rapid_diffs/stores/diffs_view'; jest.mock('~/mr_notes/stores'); jest.mock('~/rapid_diffs/app/view_settings'); +jest.mock('~/rapid_diffs/app/init_hidden_files_warning'); jest.mock('~/rapid_diffs/app/init_file_browser'); describe('Rapid Diffs App', () => { @@ -49,6 +51,7 @@ describe('Rapid Diffs App', () => { expect(window.customElements.get('diff-file-mounted')).toBe(DiffFileMounted); expect(window.customElements.get('streaming-error')).toBe(StreamingError); await res(); + expect(initHiddenFilesWarning).toHaveBeenCalled(); expect(initFileBrowser).toHaveBeenCalled(); }); diff --git a/spec/frontend/rapid_diffs/stores/diffs_view_spec.js b/spec/frontend/rapid_diffs/stores/diffs_view_spec.js index 5fde16c506e..65a74f68171 100644 --- a/spec/frontend/rapid_diffs/stores/diffs_view_spec.js +++ b/spec/frontend/rapid_diffs/stores/diffs_view_spec.js @@ -58,11 +58,20 @@ describe('Diffs view store', () => { vuexStore.state.diffs.addedLines = 1; vuexStore.state.diffs.removedLines = 2; vuexStore.state.diffs.realSize = '3'; + vuexStore.state.diffs.size = 2; + vuexStore.state.diffs.plainDiffPath = 'plain/diffs'; + vuexStore.state.diffs.emailPatchPath = 'email/patch'; + vuexStore.state.diffs.renderOverflowWarning = true; await store.loadMetadata(); expect(store.diffStats).toStrictEqual({ addedLines: 1, removedLines: 2, diffsCount: 3, + realSize: '3', + size: 2, + plainDiffPath: 'plain/diffs', + emailPatchPath: 'email/patch', + renderOverflowWarning: true, }); }); }); diff --git a/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_managers_spec.rb b/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_managers_spec.rb index 1c335358314..76dea000144 100644 --- a/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_managers_spec.rb +++ b/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_managers_spec.rb @@ -7,34 +7,34 @@ RSpec.describe Gitlab::BackgroundMigration::RecalculateShardingKeyIdForOrphanedP let(:runners) { table(:ci_runners, database: :ci, primary_key: :id) } let(:runner_machines) { table(:ci_runner_machines, database: :ci, primary_key: :id) } let(:runner_projects) { table(:ci_runner_projects, database: :ci, primary_key: :id) } - let!(:project_runner1) { runners.create!(id: 1, runner_type: 3, sharding_key_id: 10) } - let!(:project_runner2) { runners.create!(id: 2, runner_type: 3, sharding_key_id: 10) } - let!(:project_runner3) { runners.create!(id: 3, runner_type: 3, sharding_key_id: 11) } + let!(:project_runner1) { runners.create!(runner_type: 3, sharding_key_id: 10) } + let!(:project_runner2) { runners.create!(runner_type: 3, sharding_key_id: 10) } + let!(:project_runner3) { runners.create!(runner_type: 3, sharding_key_id: 11) } let!(:project_runner1_machines) do common_attrs = { runner_id: project_runner1.id, runner_type: 3, sharding_key_id: 10 } [ - runner_machines.create!(id: 1, system_xid: 'a', **common_attrs), - runner_machines.create!(id: 2, system_xid: 'b', **common_attrs) + runner_machines.create!(system_xid: 'a', **common_attrs), + runner_machines.create!(system_xid: 'b', **common_attrs) ] end let!(:project_runner2_machine) do - runner_machines.create!(id: 4, runner_id: project_runner2.id, system_xid: 'a', runner_type: 3, sharding_key_id: 10) + runner_machines.create!(runner_id: project_runner2.id, system_xid: 'a', runner_type: 3, sharding_key_id: 10) end let!(:project_runner3_machine) do - runner_machines.create!(id: 5, runner_id: project_runner3.id, system_xid: 'a', runner_type: 3, sharding_key_id: 11) + runner_machines.create!(runner_id: project_runner3.id, system_xid: 'a', runner_type: 3, sharding_key_id: 11) end - let!(:group_runner1) { runners.create!(id: 4, runner_type: 2, sharding_key_id: 10) } + let!(:group_runner1) { runners.create!(runner_type: 2, sharding_key_id: 10) } let!(:group_runner1_machine) do - runner_machines.create!(id: 6, runner_id: group_runner1.id, system_xid: 'a', runner_type: 2, sharding_key_id: 10) + runner_machines.create!(runner_id: group_runner1.id, system_xid: 'a', runner_type: 2, sharding_key_id: 10) end before do - runner_projects.create!(id: 3, project_id: 11, runner_id: project_runner2.id) - runner_projects.create!(id: 4, project_id: project_runner3.sharding_key_id, runner_id: project_runner3.id) + runner_projects.create!(project_id: 11, runner_id: project_runner2.id) + runner_projects.create!(project_id: project_runner3.sharding_key_id, runner_id: project_runner3.id) end describe '#perform' do diff --git a/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_taggings_spec.rb b/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_taggings_spec.rb index 9a1b9a6c7cd..bdf9c113a0d 100644 --- a/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_taggings_spec.rb +++ b/spec/lib/gitlab/background_migration/recalculate_sharding_key_id_for_orphaned_project_runner_taggings_spec.rb @@ -8,11 +8,11 @@ RSpec.describe Gitlab::BackgroundMigration::RecalculateShardingKeyIdForOrphanedP let(:runner_taggings) { table(:ci_runner_taggings, database: :ci, primary_key: :id) } let(:tags) { table(:tags, database: :ci, primary_key: :id) } let(:runner_projects) { table(:ci_runner_projects, database: :ci, primary_key: :id) } - let!(:project_runner1) { runners.create!(id: 1, runner_type: 3, sharding_key_id: 10) } - let!(:project_runner2) { runners.create!(id: 2, runner_type: 3, sharding_key_id: 10) } - let!(:project_runner3) { runners.create!(id: 3, runner_type: 3, sharding_key_id: 11) } - let!(:tag1) { tags.create!(id: 1, name: 'tag1') } - let!(:tag2) { tags.create!(id: 2, name: 'tag2') } + let!(:project_runner1) { runners.create!(runner_type: 3, sharding_key_id: 10) } + let!(:project_runner2) { runners.create!(runner_type: 3, sharding_key_id: 10) } + let!(:project_runner3) { runners.create!(runner_type: 3, sharding_key_id: 11) } + let!(:tag1) { tags.create!(name: 'tag1') } + let!(:tag2) { tags.create!(name: 'tag2') } let!(:project_runner1_taggings) do common_attrs = { runner_id: project_runner1.id, runner_type: 3, sharding_key_id: 10 } @@ -30,14 +30,14 @@ RSpec.describe Gitlab::BackgroundMigration::RecalculateShardingKeyIdForOrphanedP runner_taggings.create!(runner_id: project_runner3.id, tag_id: tag2.id, runner_type: 3, sharding_key_id: 11) end - let!(:group_runner1) { runners.create!(id: 4, runner_type: 2, sharding_key_id: 10) } + let!(:group_runner1) { runners.create!(runner_type: 2, sharding_key_id: 10) } let!(:group_runner1_tagging) do runner_taggings.create!(runner_id: group_runner1.id, tag_id: tag2.id, runner_type: 2, sharding_key_id: 10) end before do - runner_projects.create!(id: 3, project_id: 11, runner_id: project_runner2.id) - runner_projects.create!(id: 4, project_id: project_runner3.sharding_key_id, runner_id: project_runner3.id) + runner_projects.create!(project_id: 11, runner_id: project_runner2.id) + runner_projects.create!(project_id: project_runner3.sharding_key_id, runner_id: project_runner3.id) end describe '#perform' do diff --git a/spec/lib/gitlab/redis/cluster_sessions_spec.rb b/spec/lib/gitlab/redis/cluster_sessions_spec.rb deleted file mode 100644 index e4cfce05663..00000000000 --- a/spec/lib/gitlab/redis/cluster_sessions_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::Redis::ClusterSessions, feature_category: :scalability do - include_examples "redis_new_instance_shared_examples", 'cluster_sessions', Gitlab::Redis::SharedState -end diff --git a/spec/lib/gitlab/redis/sessions_spec.rb b/spec/lib/gitlab/redis/sessions_spec.rb index 0cfba8ed9a0..6ff261bb475 100644 --- a/spec/lib/gitlab/redis/sessions_spec.rb +++ b/spec/lib/gitlab/redis/sessions_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' RSpec.describe Gitlab::Redis::Sessions, feature_category: :shared do - include_examples "multi_store_wrapper_shared_examples" include_examples "redis_new_instance_shared_examples", 'sessions', Gitlab::Redis::SharedState describe '#store' do @@ -14,9 +13,4 @@ RSpec.describe Gitlab::Redis::Sessions, feature_category: :shared do expect([::Redis::Store, ::Gitlab::Redis::ClusterStore].include?(store.class)).to eq(true) end end - - it 'migrates from self to ClusterSessions' do - expect(described_class.multistore.secondary_pool).to eq(described_class.pool) - expect(described_class.multistore.primary_pool).to eq(Gitlab::Redis::ClusterSessions.pool) - end end diff --git a/spec/rubocop/cop/.rubocop.yml b/spec/rubocop/cop/.rubocop.yml new file mode 100644 index 00000000000..e010ffcb2e3 --- /dev/null +++ b/spec/rubocop/cop/.rubocop.yml @@ -0,0 +1,3 @@ +--- +inherit_from: + - '../../../.rubocop/internal_affairs.yml'