From 5dc70663c4ff1feb215428ce50673b5b646f9809 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 21 Nov 2022 15:12:22 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .rubocop_todo/gitlab/strong_memoize_attr.yml | 730 ++++++++++++++++++ .../javascripts/projects/new/constants.js | 2 + app/helpers/labels_helper.rb | 6 +- app/models/issue.rb | 2 +- .../incidents/create_service.rb | 2 +- app/services/issues/close_service.rb | 11 +- app/views/groups/labels/index.html.haml | 2 +- config/initializers/diagnostic_reports.rb | 4 + db/structure.sql | 2 +- doc/administration/audit_events.md | 90 +-- .../ci_pipeline_components/index.md | 2 +- doc/development/caching.md | 4 +- doc/development/secure_coding_guidelines.md | 11 +- doc/development/utilities.md | 14 - doc/update/index.md | 2 + lib/gitlab/memory/reports/heap_dump.rb | 45 ++ lib/gitlab/memory/watchdog.rb | 14 +- lib/gitlab/memory/watchdog/configuration.rb | 6 +- lib/gitlab/memory/watchdog/configurator.rb | 14 +- lib/gitlab/utils/strong_memoize.rb | 10 - locale/gitlab.pot | 15 +- .../3_create/pages/new_static_page_spec.rb | 10 +- rubocop/cop/gitlab/strong_memoize_attr.rb | 39 + spec/controllers/projects_controller_spec.rb | 16 +- spec/helpers/labels_helper_spec.rb | 23 + spec/initializers/diagnostic_reports_spec.rb | 21 +- .../gitlab/memory/reports/heap_dump_spec.rb | 23 + .../memory/watchdog/configurator_spec.rb | 42 + spec/lib/gitlab/memory/watchdog_spec.rb | 29 +- spec/lib/gitlab/utils/strong_memoize_spec.rb | 2 +- spec/models/issue_spec.rb | 2 +- .../api/graphql/project/issues_spec.rb | 2 +- spec/requests/search_controller_spec.rb | 83 +- .../cop/gitlab/strong_memoize_attr_spec.rb | 72 ++ .../incidents/create_service_spec.rb | 24 +- spec/services/issues/close_service_spec.rb | 34 +- .../projects/transfer_service_spec.rb | 14 +- spec/support/helpers/search_helpers.rb | 2 + spec/views/search/_results.html.haml_spec.rb | 66 +- 39 files changed, 1296 insertions(+), 196 deletions(-) create mode 100644 .rubocop_todo/gitlab/strong_memoize_attr.yml create mode 100644 lib/gitlab/memory/reports/heap_dump.rb create mode 100644 rubocop/cop/gitlab/strong_memoize_attr.rb create mode 100644 spec/lib/gitlab/memory/reports/heap_dump_spec.rb create mode 100644 spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb diff --git a/.rubocop_todo/gitlab/strong_memoize_attr.yml b/.rubocop_todo/gitlab/strong_memoize_attr.yml new file mode 100644 index 00000000000..d2824550042 --- /dev/null +++ b/.rubocop_todo/gitlab/strong_memoize_attr.yml @@ -0,0 +1,730 @@ +--- +# Cop supports --autocorrect. +Gitlab/StrongMemoizeAttr: + Details: grace period + Exclude: + - 'app/components/pajamas/avatar_component.rb' + - 'app/controllers/application_controller.rb' + - 'app/controllers/concerns/boards_actions.rb' + - 'app/controllers/concerns/creates_commit.rb' + - 'app/controllers/concerns/find_snippet.rb' + - 'app/controllers/concerns/impersonation.rb' + - 'app/controllers/concerns/issuable_actions.rb' + - 'app/controllers/concerns/issuable_collections.rb' + - 'app/controllers/concerns/known_sign_in.rb' + - 'app/controllers/concerns/lfs_request.rb' + - 'app/controllers/concerns/notes_actions.rb' + - 'app/controllers/concerns/snippets/blobs_actions.rb' + - 'app/controllers/concerns/uploads_actions.rb' + - 'app/controllers/concerns/wiki_actions.rb' + - 'app/controllers/google_api/authorizations_controller.rb' + - 'app/controllers/groups/boards_controller.rb' + - 'app/controllers/groups/dependency_proxy_for_containers_controller.rb' + - 'app/controllers/ide_controller.rb' + - 'app/controllers/import/github_controller.rb' + - 'app/controllers/invites_controller.rb' + - 'app/controllers/jira_connect/application_controller.rb' + - 'app/controllers/jwt_controller.rb' + - 'app/controllers/oauth/authorizations_controller.rb' + - 'app/controllers/projects/analytics/cycle_analytics/stages_controller.rb' + - 'app/controllers/projects/boards_controller.rb' + - 'app/controllers/projects/compare_controller.rb' + - 'app/controllers/projects/forks_controller.rb' + - 'app/controllers/projects/import/jira_controller.rb' + - 'app/controllers/projects/incidents_controller.rb' + - 'app/controllers/projects/merge_requests_controller.rb' + - 'app/controllers/projects/metrics_dashboard_controller.rb' + - 'app/controllers/projects/milestones_controller.rb' + - 'app/controllers/projects/pipelines/application_controller.rb' + - 'app/controllers/projects/pipelines_controller.rb' + - 'app/controllers/projects/todos_controller.rb' + - 'app/controllers/repositories/git_http_client_controller.rb' + - 'app/controllers/repositories/lfs_api_controller.rb' + - 'app/controllers/sessions_controller.rb' + - 'app/controllers/whats_new_controller.rb' + - 'app/finders/autocomplete/users_finder.rb' + - 'app/finders/ci/commit_statuses_finder.rb' + - 'app/finders/ci/pipelines_for_merge_request_finder.rb' + - 'app/finders/cluster_ancestors_finder.rb' + - 'app/finders/clusters/knative_services_finder.rb' + - 'app/finders/concerns/finder_with_group_hierarchy.rb' + - 'app/finders/crm/contacts_finder.rb' + - 'app/finders/crm/organizations_finder.rb' + - 'app/finders/groups/accepting_group_transfers_finder.rb' + - 'app/finders/issuable_finder.rb' + - 'app/finders/issuable_finder/params.rb' + - 'app/finders/issuables/label_filter.rb' + - 'app/finders/issues_finder/params.rb' + - 'app/finders/license_template_finder.rb' + - 'app/finders/merge_requests_finder/params.rb' + - 'app/finders/projects/members/effective_access_level_finder.rb' + - 'app/finders/releases/evidence_pipeline_finder.rb' + - 'app/finders/releases_finder.rb' + - 'app/finders/snippets_finder.rb' + - 'app/finders/todos_finder.rb' + - 'app/graphql/resolvers/issue_status_counts_resolver.rb' + - 'app/graphql/resolvers/issues/base_parent_resolver.rb' + - 'app/graphql/resolvers/namespace_projects_resolver.rb' + - 'app/graphql/resolvers/work_items_resolver.rb' + - 'app/graphql/types/board_list_type.rb' + - 'app/helpers/appearances_helper.rb' + - 'app/helpers/operations_helper.rb' + - 'app/helpers/page_layout_helper.rb' + - 'app/helpers/projects_helper.rb' + - 'app/helpers/sessions_helper.rb' + - 'app/helpers/timeboxes_helper.rb' + - 'app/models/alert_management/alert.rb' + - 'app/models/application_setting_implementation.rb' + - 'app/models/blob_viewer/go_mod.rb' + - 'app/models/blob_viewer/metrics_dashboard_yml.rb' + - 'app/models/bulk_imports/export.rb' + - 'app/models/bulk_imports/export_status.rb' + - 'app/models/bulk_imports/file_transfer/base_config.rb' + - 'app/models/ci/bridge.rb' + - 'app/models/ci/build.rb' + - 'app/models/ci/build_dependencies.rb' + - 'app/models/ci/build_metadata.rb' + - 'app/models/ci/commit_with_pipeline.rb' + - 'app/models/ci/group.rb' + - 'app/models/ci/job_artifact.rb' + - 'app/models/ci/pipeline.rb' + - 'app/models/ci/processable.rb' + - 'app/models/ci/runner.rb' + - 'app/models/clusters/cluster.rb' + - 'app/models/clusters/providers/aws.rb' + - 'app/models/commit.rb' + - 'app/models/commit_collection.rb' + - 'app/models/compare.rb' + - 'app/models/concerns/analytics/cycle_analytics/stage.rb' + - 'app/models/concerns/avatarable.rb' + - 'app/models/concerns/cascading_namespace_setting_attribute.rb' + - 'app/models/concerns/ci/contextable.rb' + - 'app/models/concerns/discussion_on_diff.rb' + - 'app/models/concerns/has_repository.rb' + - 'app/models/concerns/has_wiki.rb' + - 'app/models/concerns/has_wiki_page_meta_attributes.rb' + - 'app/models/concerns/redis_cacheable.rb' + - 'app/models/concerns/require_email_verification.rb' + - 'app/models/concerns/resolvable_discussion.rb' + - 'app/models/concerns/security/latest_pipeline_information.rb' + - 'app/models/container_registry/event.rb' + - 'app/models/container_repository.rb' + - 'app/models/customer_relations/contact_state_counts.rb' + - 'app/models/deploy_token.rb' + - 'app/models/deployment.rb' + - 'app/models/deployment_metrics.rb' + - 'app/models/design_management/design.rb' + - 'app/models/design_management/design_at_version.rb' + - 'app/models/design_management/version.rb' + - 'app/models/diff_note.rb' + - 'app/models/draft_note.rb' + - 'app/models/environment.rb' + - 'app/models/environment_status.rb' + - 'app/models/error_tracking/project_error_tracking_setting.rb' + - 'app/models/event.rb' + - 'app/models/event_collection.rb' + - 'app/models/group.rb' + - 'app/models/incident_management/project_incident_management_setting.rb' + - 'app/models/integrations/jira.rb' + - 'app/models/internal_id.rb' + - 'app/models/member.rb' + - 'app/models/merge_request.rb' + - 'app/models/merge_request_diff.rb' + - 'app/models/namespace.rb' + - 'app/models/note.rb' + - 'app/models/onboarding/completion.rb' + - 'app/models/packages/go/module.rb' + - 'app/models/packages/go/module_version.rb' + - 'app/models/packages/package.rb' + - 'app/models/pages/lookup_path.rb' + - 'app/models/project.rb' + - 'app/models/release.rb' + - 'app/models/resource_event.rb' + - 'app/models/service_desk_setting.rb' + - 'app/models/snippet.rb' + - 'app/models/snippet_input_action_collection.rb' + - 'app/models/state_note.rb' + - 'app/models/tree.rb' + - 'app/models/user.rb' + - 'app/models/wiki_page.rb' + - 'app/models/work_item.rb' + - 'app/policies/application_setting/term_policy.rb' + - 'app/policies/note_policy.rb' + - 'app/presenters/blobs/unfold_presenter.rb' + - 'app/presenters/ci/build_runner_presenter.rb' + - 'app/presenters/ci/pipeline_artifacts/code_coverage_presenter.rb' + - 'app/presenters/ci/pipeline_artifacts/code_quality_mr_diff_presenter.rb' + - 'app/presenters/ci/pipeline_presenter.rb' + - 'app/presenters/clusters/cluster_presenter.rb' + - 'app/presenters/merge_request_presenter.rb' + - 'app/presenters/packages/nuget/packages_metadata_presenter.rb' + - 'app/presenters/packages/nuget/search_results_presenter.rb' + - 'app/presenters/project_presenter.rb' + - 'app/presenters/projects/settings/deploy_keys_presenter.rb' + - 'app/serializers/ci/pipeline_entity.rb' + - 'app/serializers/concerns/diff_file_conflict_type.rb' + - 'app/serializers/diff_file_base_entity.rb' + - 'app/serializers/integrations/field_entity.rb' + - 'app/serializers/linked_project_issue_entity.rb' + - 'app/serializers/suggestion_entity.rb' + - 'app/services/alert_management/alerts/update_service.rb' + - 'app/services/alert_management/create_alert_issue_service.rb' + - 'app/services/alert_management/process_prometheus_alert_service.rb' + - 'app/services/auth/dependency_proxy_authentication_service.rb' + - 'app/services/authorized_project_update/project_recalculate_service.rb' + - 'app/services/auto_merge/base_service.rb' + - 'app/services/award_emojis/add_service.rb' + - 'app/services/base_project_service.rb' + - 'app/services/boards/base_items_list_service.rb' + - 'app/services/boards/lists/base_create_service.rb' + - 'app/services/ci/create_downstream_pipeline_service.rb' + - 'app/services/ci/create_web_ide_terminal_service.rb' + - 'app/services/ci/job_artifacts/destroy_batch_service.rb' + - 'app/services/ci/parse_dotenv_artifact_service.rb' + - 'app/services/ci/pipeline_artifacts/coverage_report_service.rb' + - 'app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb' + - 'app/services/ci/pipeline_artifacts/destroy_all_expired_service.rb' + - 'app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb' + - 'app/services/ci/pipeline_schedules/calculate_next_run_service.rb' + - 'app/services/ci/pipeline_trigger_service.rb' + - 'app/services/ci/pipelines/hook_service.rb' + - 'app/services/ci/queue/build_queue_service.rb' + - 'app/services/ci/update_build_state_service.rb' + - 'app/services/clusters/agents/refresh_authorization_service.rb' + - 'app/services/clusters/aws/finalize_creation_service.rb' + - 'app/services/clusters/integrations/prometheus_health_check_service.rb' + - 'app/services/concerns/alert_management/alert_processing.rb' + - 'app/services/concerns/incident_management/settings.rb' + - 'app/services/concerns/issues/resolve_discussions.rb' + - 'app/services/concerns/suggestible.rb' + - 'app/services/concerns/update_repository_storage_methods.rb' + - 'app/services/container_expiration_policies/update_service.rb' + - 'app/services/dependency_proxy/image_ttl_group_policies/update_service.rb' + - 'app/services/discussions/resolve_service.rb' + - 'app/services/error_tracking/collect_error_service.rb' + - 'app/services/error_tracking/issue_details_service.rb' + - 'app/services/feature_flags/base_service.rb' + - 'app/services/git/base_hooks_service.rb' + - 'app/services/git/branch_hooks_service.rb' + - 'app/services/git/branch_push_service.rb' + - 'app/services/git/tag_hooks_service.rb' + - 'app/services/git/wiki_push_service/change.rb' + - 'app/services/groups/open_issues_count_service.rb' + - 'app/services/import/github_service.rb' + - 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb' + - 'app/services/incident_management/issuable_escalation_statuses/prepare_update_service.rb' + - 'app/services/incident_management/pager_duty/process_webhook_service.rb' + - 'app/services/integrations/test/project_service.rb' + - 'app/services/issues/reorder_service.rb' + - 'app/services/jira_connect_subscriptions/create_service.rb' + - 'app/services/jira_import/users_mapper_service.rb' + - 'app/services/lfs/push_service.rb' + - 'app/services/markdown_content_rewriter_service.rb' + - 'app/services/members/invitation_reminder_email_service.rb' + - 'app/services/merge_requests/build_service.rb' + - 'app/services/merge_requests/merge_base_service.rb' + - 'app/services/merge_requests/mergeability/detailed_merge_status_service.rb' + - 'app/services/merge_requests/mergeability/logger.rb' + - 'app/services/merge_requests/mergeability/run_checks_service.rb' + - 'app/services/merge_requests/mergeability_check_service.rb' + - 'app/services/merge_requests/outdated_discussion_diff_lines_service.rb' + - 'app/services/merge_requests/pushed_branches_service.rb' + - 'app/services/merge_requests/refresh_service.rb' + - 'app/services/metrics/dashboard/clone_dashboard_service.rb' + - 'app/services/metrics/dashboard/custom_metric_embed_service.rb' + - 'app/services/metrics/dashboard/dynamic_embed_service.rb' + - 'app/services/metrics/dashboard/gitlab_alert_embed_service.rb' + - 'app/services/namespaces/package_settings/update_service.rb' + - 'app/services/packages/cleanup/execute_policy_service.rb' + - 'app/services/packages/cleanup/update_policy_service.rb' + - 'app/services/packages/composer/create_package_service.rb' + - 'app/services/packages/debian/extract_changes_metadata_service.rb' + - 'app/services/packages/debian/extract_metadata_service.rb' + - 'app/services/packages/debian/find_or_create_package_service.rb' + - 'app/services/packages/debian/generate_distribution_key_service.rb' + - 'app/services/packages/debian/generate_distribution_service.rb' + - 'app/services/packages/debian/process_changes_service.rb' + - 'app/services/packages/helm/process_file_service.rb' + - 'app/services/packages/maven/metadata/base_create_xml_service.rb' + - 'app/services/packages/maven/metadata/create_plugins_xml_service.rb' + - 'app/services/packages/maven/metadata/create_versions_xml_service.rb' + - 'app/services/packages/maven/metadata/sync_service.rb' + - 'app/services/packages/npm/create_package_service.rb' + - 'app/services/packages/npm/create_tag_service.rb' + - 'app/services/packages/nuget/metadata_extraction_service.rb' + - 'app/services/packages/nuget/search_service.rb' + - 'app/services/packages/nuget/sync_metadatum_service.rb' + - 'app/services/packages/nuget/update_package_from_metadata_service.rb' + - 'app/services/packages/pypi/create_package_service.rb' + - 'app/services/packages/rpm/parse_package_service.rb' + - 'app/services/packages/rubygems/dependency_resolver_service.rb' + - 'app/services/packages/rubygems/process_gem_service.rb' + - 'app/services/packages/terraform_module/create_package_service.rb' + - 'app/services/packages/update_tags_service.rb' + - 'app/services/projects/container_repository/cleanup_tags_base_service.rb' + - 'app/services/projects/container_repository/third_party/cleanup_tags_service.rb' + - 'app/services/projects/create_from_template_service.rb' + - 'app/services/projects/gitlab_projects_import_service.rb' + - 'app/services/projects/open_issues_count_service.rb' + - 'app/services/projects/record_target_platforms_service.rb' + - 'app/services/projects/update_remote_mirror_service.rb' + - 'app/services/projects/update_statistics_service.rb' + - 'app/services/prometheus/proxy_service.rb' + - 'app/services/quick_actions/interpret_service.rb' + - 'app/services/releases/base_service.rb' + - 'app/services/resource_access_tokens/revoke_service.rb' + - 'app/services/resource_events/base_synthetic_notes_builder_service.rb' + - 'app/services/search/global_service.rb' + - 'app/services/search/project_service.rb' + - 'app/services/search_service.rb' + - 'app/services/security/ci_configuration/sast_parser_service.rb' + - 'app/services/test_hooks/project_service.rb' + - 'app/services/test_hooks/system_service.rb' + - 'app/uploaders/file_mover.rb' + - 'app/uploaders/object_storage/cdn.rb' + - 'app/uploaders/object_storage/cdn/google_cdn.rb' + - 'app/workers/concerns/each_shard_worker.rb' + - 'app/workers/concerns/limited_capacity/worker.rb' + - 'app/workers/concerns/packages/cleanup_artifact_worker.rb' + - 'app/workers/container_expiration_policies/cleanup_container_repository_worker.rb' + - 'app/workers/container_registry/delete_container_repository_worker.rb' + - 'app/workers/container_registry/migration/enqueuer_worker.rb' + - 'app/workers/database/batched_background_migration/execution_worker.rb' + - 'app/workers/database/batched_background_migration/single_database_worker.rb' + - 'app/workers/error_tracking_issue_link_worker.rb' + - 'app/workers/merge_request_cleanup_refs_worker.rb' + - 'app/workers/packages/cleanup/execute_policy_worker.rb' + - 'app/workers/packages/debian/generate_distribution_worker.rb' + - 'app/workers/packages/debian/process_changes_worker.rb' + - 'app/workers/packages/maven/metadata/sync_worker.rb' + - 'app/workers/projects/inactive_projects_deletion_cron_worker.rb' + - 'ee/app/controllers/admin/audit_logs_controller.rb' + - 'ee/app/controllers/concerns/description_diff_actions.rb' + - 'ee/app/controllers/concerns/ee/lfs_request.rb' + - 'ee/app/controllers/concerns/ee/routable_actions/sso_enforcement_redirect.rb' + - 'ee/app/controllers/concerns/epic_relations.rb' + - 'ee/app/controllers/ee/admin/health_check_controller.rb' + - 'ee/app/controllers/ee/groups/settings/repository_controller.rb' + - 'ee/app/controllers/ee/groups_controller.rb' + - 'ee/app/controllers/ee/registrations/welcome_controller.rb' + - 'ee/app/controllers/ee/repositories/git_http_controller.rb' + - 'ee/app/controllers/groups/audit_events_controller.rb' + - 'ee/app/controllers/groups/epic_boards_controller.rb' + - 'ee/app/controllers/groups/push_rules_controller.rb' + - 'ee/app/controllers/groups/todos_controller.rb' + - 'ee/app/controllers/projects/audit_events_controller.rb' + - 'ee/app/controllers/projects/subscriptions_controller.rb' + - 'ee/app/controllers/subscriptions_controller.rb' + - 'ee/app/finders/approval_rules/group_finder.rb' + - 'ee/app/finders/concerns/epics/with_access_check.rb' + - 'ee/app/finders/ee/issues_finder.rb' + - 'ee/app/finders/epics_finder.rb' + - 'ee/app/finders/incident_management/oncall_users_finder.rb' + - 'ee/app/finders/requirements_management/requirements_finder.rb' + - 'ee/app/finders/security/pipeline_vulnerabilities_finder.rb' + - 'ee/app/finders/security/training_providers/base_url_finder.rb' + - 'ee/app/graphql/resolvers/epics_resolver.rb' + - 'ee/app/graphql/resolvers/vulnerabilities_base_resolver.rb' + - 'ee/app/helpers/admin/emails_helper.rb' + - 'ee/app/helpers/auditor_user_helper.rb' + - 'ee/app/helpers/billing_plans_helper.rb' + - 'ee/app/helpers/ee/ci/runners_helper.rb' + - 'ee/app/helpers/ee/preferences_helper.rb' + - 'ee/app/helpers/ee/registrations_helper.rb' + - 'ee/app/helpers/ee/timeboxes_helper.rb' + - 'ee/app/helpers/ee/trial_helper.rb' + - 'ee/app/helpers/ee/welcome_helper.rb' + - 'ee/app/helpers/license_monitoring_helper.rb' + - 'ee/app/helpers/paid_feature_callout_helper.rb' + - 'ee/app/helpers/trial_status_widget_helper.rb' + - 'ee/app/models/approval_merge_request_rule.rb' + - 'ee/app/models/approval_state.rb' + - 'ee/app/models/approval_wrapped_any_approver_rule.rb' + - 'ee/app/models/approval_wrapped_code_owner_rule.rb' + - 'ee/app/models/approval_wrapped_rule.rb' + - 'ee/app/models/approvals/scan_finding_wrapped_rule_set.rb' + - 'ee/app/models/approvals/wrapped_rule_set.rb' + - 'ee/app/models/ci/minutes/limit.rb' + - 'ee/app/models/concerns/deprecated_approvals_before_merge.rb' + - 'ee/app/models/concerns/ee/approvable.rb' + - 'ee/app/models/concerns/ee/issue_available_features.rb' + - 'ee/app/models/concerns/insights_feature.rb' + - 'ee/app/models/concerns/security/scan_execution_policy.rb' + - 'ee/app/models/deployments/approval_summary.rb' + - 'ee/app/models/ee/audit_event.rb' + - 'ee/app/models/ee/ci/bridge.rb' + - 'ee/app/models/ee/ci/build.rb' + - 'ee/app/models/ee/ci/build_dependencies.rb' + - 'ee/app/models/ee/ci/job_artifact.rb' + - 'ee/app/models/ee/ci/runner.rb' + - 'ee/app/models/ee/deployment.rb' + - 'ee/app/models/ee/environment.rb' + - 'ee/app/models/ee/group.rb' + - 'ee/app/models/ee/integrations/jira.rb' + - 'ee/app/models/ee/list.rb' + - 'ee/app/models/ee/merge_request.rb' + - 'ee/app/models/ee/namespace.rb' + - 'ee/app/models/ee/namespace/storage/notification.rb' + - 'ee/app/models/ee/project.rb' + - 'ee/app/models/ee/snippet.rb' + - 'ee/app/models/ee/user.rb' + - 'ee/app/models/ee/work_item.rb' + - 'ee/app/models/gitlab/seat_link_data.rb' + - 'ee/app/models/gitlab_subscription.rb' + - 'ee/app/models/issuables_analytics.rb' + - 'ee/app/models/license.rb' + - 'ee/app/models/namespaces/storage/root_excess_size.rb' + - 'ee/app/models/sca/license_compliance.rb' + - 'ee/app/models/security/orchestration_policy_configuration.rb' + - 'ee/app/models/security/orchestration_policy_rule_schedule.rb' + - 'ee/app/models/vulnerabilities/finding.rb' + - 'ee/app/presenters/approval_rule_presenter.rb' + - 'ee/app/presenters/ci/minutes/usage_presenter.rb' + - 'ee/app/presenters/merge_request_approver_presenter.rb' + - 'ee/app/serializers/dashboard_operations_project_entity.rb' + - 'ee/app/serializers/ee/member_user_entity.rb' + - 'ee/app/services/app_sec/dast/pipelines/find_latest_service.rb' + - 'ee/app/services/app_sec/dast/scan_configs/build_service.rb' + - 'ee/app/services/approval_rules/params_filtering_service.rb' + - 'ee/app/services/boards/epics/position_create_service.rb' + - 'ee/app/services/ci/compare_license_scanning_reports_collapsed_service.rb' + - 'ee/app/services/ci/minutes/update_project_and_namespace_usage_service.rb' + - 'ee/app/services/ci/subscribe_bridge_service.rb' + - 'ee/app/services/ci/sync_reports_to_approval_rules_service.rb' + - 'ee/app/services/deployments/approval_service.rb' + - 'ee/app/services/ee/allowed_email_domains/update_service.rb' + - 'ee/app/services/ee/auto_merge_service.rb' + - 'ee/app/services/ee/boards/lists/create_service.rb' + - 'ee/app/services/ee/ci/retry_pipeline_service.rb' + - 'ee/app/services/ee/incident_management/issuable_escalation_statuses/prepare_update_service.rb' + - 'ee/app/services/ee/integrations/test/project_service.rb' + - 'ee/app/services/ee/ip_restrictions/update_service.rb' + - 'ee/app/services/ee/issuable_base_service.rb' + - 'ee/app/services/ee/issues/export_csv_service.rb' + - 'ee/app/services/ee/merge_requests/merge_base_service.rb' + - 'ee/app/services/ee/post_receive_service.rb' + - 'ee/app/services/ee/projects/create_from_template_service.rb' + - 'ee/app/services/ee/projects/gitlab_projects_import_service.rb' + - 'ee/app/services/ee/protected_branches/create_service.rb' + - 'ee/app/services/ee/search/global_service.rb' + - 'ee/app/services/ee/search_service.rb' + - 'ee/app/services/ee/users/build_service.rb' + - 'ee/app/services/ee/users/update_service.rb' + - 'ee/app/services/elastic/cluster_reindexing_service.rb' + - 'ee/app/services/epic_issues/list_service.rb' + - 'ee/app/services/epics/descendant_count_service.rb' + - 'ee/app/services/epics/related_epic_links/destroy_service.rb' + - 'ee/app/services/geo/container_repository_sync.rb' + - 'ee/app/services/geo/event_service.rb' + - 'ee/app/services/geo/file_registry_removal_service.rb' + - 'ee/app/services/geo/repository_destroy_service.rb' + - 'ee/app/services/gitlab_subscriptions/activate_service.rb' + - 'ee/app/services/gitlab_subscriptions/create_service.rb' + - 'ee/app/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service.rb' + - 'ee/app/services/gitlab_subscriptions/reconciliations/calculate_seat_count_data_service.rb' + - 'ee/app/services/groups/sync_service.rb' + - 'ee/app/services/incident_management/escalation_policies/update_service.rb' + - 'ee/app/services/incident_management/pending_escalations/process_service.rb' + - 'ee/app/services/iterations/create_service.rb' + - 'ee/app/services/merge_commits/export_csv_service.rb' + - 'ee/app/services/merge_requests/update_blocks_service.rb' + - 'ee/app/services/projects/restore_service.rb' + - 'ee/app/services/projects/update_mirror_service.rb' + - 'ee/app/services/protected_environments/base_service.rb' + - 'ee/app/services/security/ingestion/tasks/ingest_vulnerabilities/mark_resolved_as_detected.rb' + - 'ee/app/services/security/report_fetch_service.rb' + - 'ee/app/services/security/report_summary_service.rb' + - 'ee/app/services/security/security_orchestration_policies/on_demand_scan_pipeline_configuration_service.rb' + - 'ee/app/services/security/security_orchestration_policies/operational_vulnerabilities_configuration_service.rb' + - 'ee/app/services/security/security_orchestration_policies/validate_policy_service.rb' + - 'ee/app/services/status_page/publish_attachments_service.rb' + - 'ee/app/services/status_page/publish_base_service.rb' + - 'ee/app/services/status_page/publish_service.rb' + - 'ee/app/services/status_page/trigger_publish_service.rb' + - 'ee/app/services/timebox_report_service.rb' + - 'ee/app/services/vulnerabilities/create_service.rb' + - 'ee/app/services/vulnerability_feedback/create_service.rb' + - 'ee/app/services/vulnerability_feedback/destroy_service.rb' + - 'ee/app/workers/auth/saml_group_sync_worker.rb' + - 'ee/app/workers/geo/repository_cleanup_worker.rb' + - 'ee/app/workers/group_saml_group_sync_worker.rb' + - 'ee/app/workers/status_page/publish_worker.rb' + - 'ee/lib/api/analytics/project_deployment_frequency.rb' + - 'ee/lib/api/epic_links.rb' + - 'ee/lib/api/geo_nodes.rb' + - 'ee/lib/api/vulnerability_exports.rb' + - 'ee/lib/api/vulnerability_findings.rb' + - 'ee/lib/ee/api/geo.rb' + - 'ee/lib/ee/banzai/filter/references/reference_cache.rb' + - 'ee/lib/ee/container_registry/client.rb' + - 'ee/lib/ee/gitlab/alert_management/payload/generic.rb' + - 'ee/lib/ee/gitlab/analytics/cycle_analytics/data_collector.rb' + - 'ee/lib/ee/gitlab/analytics/cycle_analytics/stage_events.rb' + - 'ee/lib/ee/gitlab/auth/o_auth/auth_hash.rb' + - 'ee/lib/ee/gitlab/background_migration/backfill_project_statistics_container_repository_size.rb' + - 'ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb' + - 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb' + - 'ee/lib/ee/gitlab/checks/base_checker.rb' + - 'ee/lib/ee/gitlab/checks/diff_check.rb' + - 'ee/lib/ee/gitlab/ci/matching/runner_matcher.rb' + - 'ee/lib/ee/gitlab/ci/pipeline/chain/validate/external.rb' + - 'ee/lib/ee/gitlab/ci/pipeline/quota/activity.rb' + - 'ee/lib/ee/gitlab/ci/pipeline/quota/size.rb' + - 'ee/lib/ee/gitlab/etag_caching/router/rails.rb' + - 'ee/lib/ee/gitlab/git_access.rb' + - 'ee/lib/ee/gitlab/gitaly_client/with_feature_flag_actors.rb' + - 'ee/lib/ee/gitlab/import_export/after_export_strategies/custom_template_export_import_strategy.rb' + - 'ee/lib/ee/gitlab/issuable_metadata.rb' + - 'ee/lib/ee/gitlab/scim/deprovision_service.rb' + - 'ee/lib/ee/gitlab/scim/provisioning_service.rb' + - 'ee/lib/ee/gitlab/security/scan_configuration.rb' + - 'ee/lib/ee/gitlab/web_hooks/rate_limiter.rb' + - 'ee/lib/ee/sidebars/groups/menus/issues_menu.rb' + - 'ee/lib/ee/sidebars/groups/menus/settings_menu.rb' + - 'ee/lib/elastic/multi_version_util.rb' + - 'ee/lib/gitlab/auth/group_saml/auth_hash.rb' + - 'ee/lib/gitlab/auth/group_saml/membership_updater.rb' + - 'ee/lib/gitlab/auth/group_saml/user.rb' + - 'ee/lib/gitlab/auth/saml/membership_updater.rb' + - 'ee/lib/gitlab/auth/smartcard/certificate.rb' + - 'ee/lib/gitlab/ci/minutes/build_consumption.rb' + - 'ee/lib/gitlab/ci/minutes/cached_quota.rb' + - 'ee/lib/gitlab/ci/minutes/gitlab_contribution_cost_factor.rb' + - 'ee/lib/gitlab/ci/minutes/runners_availability.rb' + - 'ee/lib/gitlab/ci/parsers/security/container_scanning.rb' + - 'ee/lib/gitlab/ci/project_config/compliance.rb' + - 'ee/lib/gitlab/ci/reports/license_scanning/reports_comparer.rb' + - 'ee/lib/gitlab/ci/reports/metrics/reports_comparer.rb' + - 'ee/lib/gitlab/code_owners/entry.rb' + - 'ee/lib/gitlab/code_owners/loader.rb' + - 'ee/lib/gitlab/custom_file_templates.rb' + - 'ee/lib/gitlab/elastic/document_reference.rb' + - 'ee/lib/gitlab/elastic/indexer.rb' + - 'ee/lib/gitlab/elastic/search_results.rb' + - 'ee/lib/gitlab/expiring_subscription_message.rb' + - 'ee/lib/gitlab/geo/health_check.rb' + - 'ee/lib/gitlab/geo/jwt_request_decoder.rb' + - 'ee/lib/gitlab/geo/oauth/logout_state.rb' + - 'ee/lib/gitlab/geo/oauth/logout_token.rb' + - 'ee/lib/gitlab/geo/oauth/session.rb' + - 'ee/lib/gitlab/geo/replication/blob_retriever.rb' + - 'ee/lib/gitlab/graphql/aggregations/epics/epic_node.rb' + - 'ee/lib/gitlab/ingestion/bulk_insertable_task.rb' + - 'ee/lib/gitlab/ingestion/bulk_updatable_task.rb' + - 'ee/lib/gitlab/insights/finders/issuable_finder.rb' + - 'ee/lib/gitlab/insights/finders/projects_finder.rb' + - 'ee/lib/gitlab/manual_quarterly_co_term_banner.rb' + - 'ee/lib/gitlab/return_to_location.rb' + - 'ee/lib/gitlab_subscriptions/upcoming_reconciliation_entity.rb' + - 'ee/lib/incident_management/oncall_shift_generator.rb' + - 'ee/lib/sidebars/groups/menus/analytics_menu.rb' + - 'ee/lib/sidebars/groups/menus/epics_menu.rb' + - 'ee/lib/world.rb' + - 'lib/api/api_guard.rb' + - 'lib/api/ci/helpers/runner.rb' + - 'lib/api/ci/pipelines.rb' + - 'lib/api/commit_statuses.rb' + - 'lib/api/composer_packages.rb' + - 'lib/api/container_repositories.rb' + - 'lib/api/entities/basic_project_details.rb' + - 'lib/api/helpers/packages/basic_auth_helpers.rb' + - 'lib/api/helpers/packages/conan/api_helpers.rb' + - 'lib/api/helpers/packages/npm.rb' + - 'lib/api/helpers/packages_helpers.rb' + - 'lib/api/terraform/modules/v1/packages.rb' + - 'lib/api/unleash.rb' + - 'lib/atlassian/jira_connect/jwt/asymmetric.rb' + - 'lib/atlassian/jira_connect/jwt/symmetric.rb' + - 'lib/banzai/filter/base_sanitization_filter.rb' + - 'lib/banzai/filter/custom_emoji_filter.rb' + - 'lib/banzai/filter/inline_metrics_redactor_filter.rb' + - 'lib/banzai/filter/issuable_reference_expansion_filter.rb' + - 'lib/banzai/filter/references/reference_cache.rb' + - 'lib/banzai/filter/repository_link_filter.rb' + - 'lib/bulk_imports/clients/http.rb' + - 'lib/bulk_imports/pipeline.rb' + - 'lib/bulk_imports/users_mapper.rb' + - 'lib/container_registry/client.rb' + - 'lib/container_registry/gitlab_api_client.rb' + - 'lib/container_registry/tag.rb' + - 'lib/flowdock/git/builder.rb' + - 'lib/gitlab/alert_management/alert_status_counts.rb' + - 'lib/gitlab/alert_management/payload/base.rb' + - 'lib/gitlab/alert_management/payload/managed_prometheus.rb' + - 'lib/gitlab/analytics/cycle_analytics/aggregated/data_collector.rb' + - 'lib/gitlab/analytics/cycle_analytics/aggregated/records_fetcher.rb' + - 'lib/gitlab/analytics/cycle_analytics/average.rb' + - 'lib/gitlab/analytics/cycle_analytics/data_collector.rb' + - 'lib/gitlab/analytics/cycle_analytics/records_fetcher.rb' + - 'lib/gitlab/application_context.rb' + - 'lib/gitlab/auth/atlassian/identity_linker.rb' + - 'lib/gitlab/auth/auth_finders.rb' + - 'lib/gitlab/auth/ip_rate_limiter.rb' + - 'lib/gitlab/auth/key_status_checker.rb' + - 'lib/gitlab/auth/otp/strategies/forti_token_cloud.rb' + - 'lib/gitlab/auth/request_authenticator.rb' + - 'lib/gitlab/background_migration/legacy_upload_mover.rb' + - 'lib/gitlab/bare_repository_import/repository.rb' + - 'lib/gitlab/blob_helper.rb' + - 'lib/gitlab/cache/ci/project_pipeline_status.rb' + - 'lib/gitlab/chat/command.rb' + - 'lib/gitlab/checks/changes_access.rb' + - 'lib/gitlab/checks/diff_check.rb' + - 'lib/gitlab/ci/artifacts/metrics.rb' + - 'lib/gitlab/ci/build/auto_retry.rb' + - 'lib/gitlab/ci/build/cache.rb' + - 'lib/gitlab/ci/build/context/base.rb' + - 'lib/gitlab/ci/build/context/build.rb' + - 'lib/gitlab/ci/build/context/global.rb' + - 'lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb' + - 'lib/gitlab/ci/build/rules/rule/clause/changes.rb' + - 'lib/gitlab/ci/config/entry/product/matrix.rb' + - 'lib/gitlab/ci/config/entry/root.rb' + - 'lib/gitlab/ci/config/extendable/entry.rb' + - 'lib/gitlab/ci/config/external/context.rb' + - 'lib/gitlab/ci/config/external/file/artifact.rb' + - 'lib/gitlab/ci/config/external/file/base.rb' + - 'lib/gitlab/ci/config/external/file/local.rb' + - 'lib/gitlab/ci/config/external/file/project.rb' + - 'lib/gitlab/ci/config/external/file/remote.rb' + - 'lib/gitlab/ci/config/external/file/template.rb' + - 'lib/gitlab/ci/config/normalizer.rb' + - 'lib/gitlab/ci/config/normalizer/factory.rb' + - 'lib/gitlab/ci/pipeline/chain/command.rb' + - 'lib/gitlab/ci/pipeline/chain/config/content.rb' + - 'lib/gitlab/ci/pipeline/chain/create.rb' + - 'lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules.rb' + - 'lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb' + - 'lib/gitlab/ci/pipeline/chain/limit/rate_limit.rb' + - 'lib/gitlab/ci/pipeline/chain/seed.rb' + - 'lib/gitlab/ci/pipeline/expression/lexer.rb' + - 'lib/gitlab/ci/pipeline/logger.rb' + - 'lib/gitlab/ci/pipeline/quota/deployments.rb' + - 'lib/gitlab/ci/pipeline/seed/build.rb' + - 'lib/gitlab/ci/pipeline/seed/pipeline.rb' + - 'lib/gitlab/ci/pipeline/seed/processable/resource_group.rb' + - 'lib/gitlab/ci/pipeline/seed/stage.rb' + - 'lib/gitlab/ci/project_config/auto_devops.rb' + - 'lib/gitlab/ci/project_config/external_project.rb' + - 'lib/gitlab/ci/project_config/parameter.rb' + - 'lib/gitlab/ci/project_config/remote.rb' + - 'lib/gitlab/ci/project_config/repository.rb' + - 'lib/gitlab/ci/project_config/source.rb' + - 'lib/gitlab/ci/reports/accessibility_reports_comparer.rb' + - 'lib/gitlab/ci/reports/codequality_reports_comparer.rb' + - 'lib/gitlab/ci/reports/security/locations/base.rb' + - 'lib/gitlab/ci/reports/security/vulnerability_reports_comparer.rb' + - 'lib/gitlab/ci/reports/test_reports_comparer.rb' + - 'lib/gitlab/ci/reports/test_suite_comparer.rb' + - 'lib/gitlab/ci/reports/test_suite_summary.rb' + - 'lib/gitlab/ci/tags/bulk_insert.rb' + - 'lib/gitlab/ci/trace.rb' + - 'lib/gitlab/ci/trace/archive.rb' + - 'lib/gitlab/ci/trace/checksum.rb' + - 'lib/gitlab/ci/trace/remote_checksum.rb' + - 'lib/gitlab/ci/variables/builder.rb' + - 'lib/gitlab/ci/variables/builder/group.rb' + - 'lib/gitlab/ci/variables/builder/release.rb' + - 'lib/gitlab/ci/variables/collection/item.rb' + - 'lib/gitlab/ci/variables/collection/sort.rb' + - 'lib/gitlab/cleanup/orphan_job_artifact_files.rb' + - 'lib/gitlab/cleanup/orphan_job_artifact_files_batch.rb' + - 'lib/gitlab/code_navigation_path.rb' + - 'lib/gitlab/config/entry/composable_array.rb' + - 'lib/gitlab/config/loader/yaml.rb' + - 'lib/gitlab/conflict/file.rb' + - 'lib/gitlab/database/background_migration/health_status/indicators/write_ahead_log.rb' + - 'lib/gitlab/database/bulk_update.rb' + - 'lib/gitlab/database/load_balancing/srv_resolver.rb' + - 'lib/gitlab/database/metrics.rb' + - 'lib/gitlab/database/postgres_index.rb' + - 'lib/gitlab/diff/char_diff.rb' + - 'lib/gitlab/diff/file.rb' + - 'lib/gitlab/diff/file_collection/base.rb' + - 'lib/gitlab/diff/file_collection/merge_request_diff_base.rb' + - 'lib/gitlab/diff/file_collection/merge_request_diff_batch.rb' + - 'lib/gitlab/diff/highlight_cache.rb' + - 'lib/gitlab/diff/lines_unfolder.rb' + - 'lib/gitlab/diff/rendered/notebook/diff_file.rb' + - 'lib/gitlab/diff/stats_cache.rb' + - 'lib/gitlab/diff/suggestion.rb' + - 'lib/gitlab/discussions_diff/file_collection.rb' + - 'lib/gitlab/email/handler/service_desk_handler.rb' + - 'lib/gitlab/email/receiver.rb' + - 'lib/gitlab/external_authorization/response.rb' + - 'lib/gitlab/gfm/reference_rewriter.rb' + - 'lib/gitlab/gfm/uploads_rewriter.rb' + - 'lib/gitlab/git/commit.rb' + - 'lib/gitlab/git/diff_stats_collection.rb' + - 'lib/gitlab/git/push.rb' + - 'lib/gitlab/git/repository.rb' + - 'lib/gitlab/git/wiki_page_version.rb' + - 'lib/gitlab/git_access.rb' + - 'lib/gitlab/git_access_project.rb' + - 'lib/gitlab/gitaly_client/with_feature_flag_actors.rb' + - 'lib/gitlab/github_import/client.rb' + - 'lib/gitlab/github_import/importer/repository_importer.rb' + - 'lib/gitlab/github_import/representation/diff_note.rb' + - 'lib/gitlab/github_import/representation/diff_notes/suggestion_formatter.rb' + - 'lib/gitlab/gl_repository/identifier.rb' + - 'lib/gitlab/gpg/commit.rb' + - 'lib/gitlab/graphql/lazy.rb' + - 'lib/gitlab/graphql/pagination/keyset/connection.rb' + - 'lib/gitlab/import_export/base/relation_factory.rb' + - 'lib/gitlab/import_export/base/relation_object_saver.rb' + - 'lib/gitlab/import_export/decompressed_archive_size_validator.rb' + - 'lib/gitlab/import_export/fast_hash_serializer.rb' + - 'lib/gitlab/import_export/group/legacy_tree_restorer.rb' + - 'lib/gitlab/import_export/group/tree_restorer.rb' + - 'lib/gitlab/import_export/importer.rb' + - 'lib/gitlab/import_export/json/legacy_reader.rb' + - 'lib/gitlab/import_export/lfs_restorer.rb' + - 'lib/gitlab/import_export/project/sample/date_calculator.rb' + - 'lib/gitlab/import_export/project/tree_restorer.rb' + - 'lib/gitlab/inactive_projects_deletion_warning_tracker.rb' + - 'lib/gitlab/instrumentation/redis_base.rb' + - 'lib/gitlab/instrumentation/redis_payload.rb' + - 'lib/gitlab/issuable_metadata.rb' + - 'lib/gitlab/jwt_authenticatable.rb' + - 'lib/gitlab/kubernetes/deployment.rb' + - 'lib/gitlab/kubernetes/ingress.rb' + - 'lib/gitlab/kubernetes/rollout_instances.rb' + - 'lib/gitlab/lets_encrypt/client.rb' + - 'lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb' + - 'lib/gitlab/metrics/dashboard/url.rb' + - 'lib/gitlab/metrics/prometheus.rb' + - 'lib/gitlab/pages/cache_control.rb' + - 'lib/gitlab/prometheus_client.rb' + - 'lib/gitlab/rack_attack/request.rb' + - 'lib/gitlab/redis/multi_store.rb' + - 'lib/gitlab/relative_positioning/ending_at.rb' + - 'lib/gitlab/relative_positioning/item_context.rb' + - 'lib/gitlab/relative_positioning/starting_from.rb' + - 'lib/gitlab/request_context.rb' + - 'lib/gitlab/search/found_blob.rb' + - 'lib/gitlab/serverless/service.rb' + - 'lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb' + - 'lib/gitlab/sidekiq_queue.rb' + - 'lib/gitlab/signed_commit.rb' + - 'lib/gitlab/ssh/signature.rb' + - 'lib/gitlab/suggestions/file_suggestion.rb' + - 'lib/gitlab/task_helpers.rb' + - 'lib/gitlab/template/gitlab_ci_yml_template.rb' + - 'lib/gitlab/tracking/destinations/snowplow_micro.rb' + - 'lib/gitlab/usage_data.rb' + - 'lib/gitlab/web_hooks/rate_limiter.rb' + - 'lib/gitlab/web_ide/config/entry/terminal.rb' + - 'lib/gitlab/webpack/graphql_known_operations.rb' + - 'lib/gitlab/wiki_pages/front_matter_parser.rb' + - 'lib/gitlab/x509/signature.rb' + - 'lib/gitlab/x509/tag.rb' + - 'lib/grafana/time_window.rb' + - 'lib/object_storage/direct_upload.rb' + - 'lib/safe_zip/extract_params.rb' + - 'lib/sidebars/groups/menus/issues_menu.rb' + - 'lib/sidebars/groups/menus/merge_requests_menu.rb' + - 'lib/sidebars/projects/menus/analytics_menu.rb' + - 'lib/sidebars/projects/menus/issues_menu.rb' + - 'lib/sidebars/projects/menus/learn_gitlab_menu.rb' + - 'lib/unnested_in_filters/rewriter.rb' + - 'tooling/graphql/docs/helper.rb' diff --git a/app/assets/javascripts/projects/new/constants.js b/app/assets/javascripts/projects/new/constants.js index e52a84dc07e..7b6b2cfc7ca 100644 --- a/app/assets/javascripts/projects/new/constants.js +++ b/app/assets/javascripts/projects/new/constants.js @@ -12,6 +12,8 @@ export const DEPLOYMENT_TARGET_SELECTIONS = [ s__('DeploymentTarget|Registry (package or container)'), s__('DeploymentTarget|Infrastructure provider (Terraform, Cloudformation, and so on)'), s__('DeploymentTarget|Serverless backend (Lambda, Cloud functions)'), + s__('DeploymentTarget|Edge Computing (e.g. Cloudflare Workers)'), + s__('DeploymentTarget|Web Deployment Platform (Netlify, Vercel, Gatsby)'), s__('DeploymentTarget|GitLab Pages'), s__('DeploymentTarget|Other hosting service'), s__('DeploymentTarget|No deployment planned'), diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 0123eb68c9a..8c069bc828b 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -159,7 +159,7 @@ module LabelsHelper end def label_subscription_toggle_button_text(label, project = nil) - label.subscribed?(current_user, project) ? 'Unsubscribe' : 'Subscribe' + label.subscribed?(current_user, project) ? _('Unsubscribe') : _('Subscribe') end def create_label_title(subject) @@ -219,8 +219,8 @@ module LabelsHelper }.merge(opts) end - def issuable_types - ['issues', 'merge requests'] + def labels_function_introduction + _('Labels can be applied to issues and merge requests. Group labels are available for any project within the group.') end def show_labels_full_path?(project, group) diff --git a/app/models/issue.rb b/app/models/issue.rb index fc083002c41..bf8e714f460 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -91,7 +91,7 @@ class Issue < ApplicationRecord has_one :incident_management_issuable_escalation_status, class_name: 'IncidentManagement::IssuableEscalationStatus' has_and_belongs_to_many :self_managed_prometheus_alert_events, join_table: :issues_self_managed_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany has_and_belongs_to_many :prometheus_alert_events, join_table: :issues_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany - has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :issue + has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :issue, validate: false has_many :prometheus_alerts, through: :prometheus_alert_events has_many :issue_customer_relations_contacts, class_name: 'CustomerRelations::IssueContact', inverse_of: :issue has_many :customer_relations_contacts, through: :issue_customer_relations_contacts, source: :contact, class_name: 'CustomerRelations::Contact', inverse_of: :issues diff --git a/app/services/incident_management/incidents/create_service.rb b/app/services/incident_management/incidents/create_service.rb index f44842650b7..49019278871 100644 --- a/app/services/incident_management/incidents/create_service.rb +++ b/app/services/incident_management/incidents/create_service.rb @@ -23,7 +23,7 @@ module IncidentManagement description: description, issue_type: ISSUE_TYPE, severity: severity, - alert_management_alert: alert + alert_management_alerts: [alert].compact }, spam_params: nil ).execute diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index da888386e0a..9f7da012c5c 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -56,7 +56,7 @@ module Issues end def perform_incident_management_actions(issue) - resolve_alert(issue) + resolve_alerts(issue) resolve_incident(issue) end @@ -71,10 +71,15 @@ module Issues SystemNoteService.change_status(issue, issue.project, current_user, issue.state, current_commit) end - def resolve_alert(issue) - return unless alert = issue.alert_management_alert + def resolve_alerts(issue) + issue.alert_management_alerts.each { |alert| resolve_alert(alert) } + end + + def resolve_alert(alert) return if alert.resolved? + issue = alert.issue + if alert.resolve SystemNoteService.change_alert_status(alert, current_user, " by closing incident #{issue.to_reference(project)}") else diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml index 8187dda5471..a03c406acc6 100644 --- a/app/views/groups/labels/index.html.haml +++ b/app/views/groups/labels/index.html.haml @@ -11,7 +11,7 @@ .labels-container.gl-mt-5 - if @labels.any? .text-muted.gl-mb-5 - = _('Labels can be applied to %{features}. Group labels are available for any project within the group.') % { features: issuable_types.to_sentence } + = labels_function_introduction .other-labels %h4= _('Labels') %ul.manage-labels-list.js-other-labels diff --git a/config/initializers/diagnostic_reports.rb b/config/initializers/diagnostic_reports.rb index 47266f99f2d..7e96c266b23 100644 --- a/config/initializers/diagnostic_reports.rb +++ b/config/initializers/diagnostic_reports.rb @@ -7,3 +7,7 @@ return unless Gitlab::Runtime.puma? Gitlab::Cluster::LifecycleEvents.on_worker_start do Gitlab::Memory::ReportsDaemon.instance.start end + +Gitlab::Cluster::LifecycleEvents.on_worker_stop do + Gitlab::Memory::Reports::HeapDump.write_conditionally +end diff --git a/db/structure.sql b/db/structure.sql index 504a7522feb..26d55c94b8e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -30332,7 +30332,7 @@ CREATE UNIQUE INDEX index_project_repository_states_on_project_id ON project_rep CREATE INDEX index_project_repository_storage_moves_on_project_id ON project_repository_storage_moves USING btree (project_id); -CREATE INDEX index_project_settings_on_legacy_os_license_project_id ON project_settings USING btree (legacy_open_source_license_available, project_id) WHERE (legacy_open_source_license_available = true); +CREATE INDEX index_project_settings_on_legacy_os_license_project_id ON project_settings USING btree (project_id) WHERE (legacy_open_source_license_available = true); CREATE INDEX index_project_settings_on_project_id_partially ON project_settings USING btree (project_id) WHERE (has_vulnerabilities IS TRUE); diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index 0aa0d163972..d10c1616eaf 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -21,17 +21,46 @@ NOTE: You can't configure a retention policy for audit events, but epic [7917](https://gitlab.com/groups/gitlab-org/-/epics/7917) proposes to change this. +## View audit events + +Depending on the events you want to view, at a minimum you must have: + +- For group audit events of all users in the group, the Owner role for the group. +- For project audit events of all users in the project, the Maintainer role for the project. +- For group and project audit events based on your own actions, the Developer role for the group or project. +- [Auditor users](auditor_users.md) can see group and project events for all users. + +You can view audit events scoped to a group or project. + +To view a group's audit events: + +1. Go to the group. +1. On the left sidebar, select **Security & Compliance > Audit Events**. + +Group events do not include project audit events. Group events can also be accessed using the +[Group Audit Events API](../api/audit_events.md#group-audit-events). Group event queries are limited to a maximum of 30 +days. + +To view a project's audit events: + +1. Go to the project. +1. On the left sidebar, select **Security & Compliance > Audit Events**. + +Project events can also be accessed using the [Project Audit Events API](../api/audit_events.md#project-audit-events). +Project event queries are limited to a maximum of 30 days. + +### View instance audit events **(PREMIUM SELF)** + +You can view audit events from user actions across an entire GitLab instance. + +To view instance audit events: + +1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, select **Monitoring > Audit Events**. + ## List of events -There are two kinds of events logged: - -- Events scoped to the group or project, used by group and project managers - to look up who made a change. -- Instance events scoped to the whole GitLab instance, used by your Compliance team to - perform formal audits. - -NOTE: -Some events are recorded and available only as [streaming audit events](audit_event_streaming.md). +You can view different events depending on the version of GitLab you have. ### Impersonation data @@ -51,19 +80,7 @@ When a user is being [impersonated](../user/admin_area/index.md#user-impersonati ### Group events -A user with: - -- Owner role (or above) can retrieve group audit events of all users. -- Developer or Maintainer role is limited to group audit events based on their individual actions. - -Group events do not include project audit events. - -To view a group's audit events: - -1. Go to the group. -1. On the left sidebar, select **Security & Compliance > Audit Events**. - -From there, you can see the following actions: +The following actions on groups generate group audit events: - Group name or path changed. - Group repository size limit changed. @@ -111,19 +128,9 @@ From there, you can see the following actions: - Changes to streaming audit destination custom HTTP headers. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366350) in GitLab 15.3. - Group had a security policy project linked, changed, or unlinked. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6) -Group events can also be accessed via the [Group Audit Events API](../api/audit_events.md#group-audit-events) - ### Project events -A user with a Maintainer role (or above) can retrieve project audit events of all users. -A user with a Developer role is limited to project audit events based on their individual actions. - -To view a project's audit events: - -1. Go to the project. -1. On the left sidebar, select **Security & Compliance > Audit Events**. - -From there, you can see the following actions: +The following actions on projects generate project audit events: - Added or removed deploy keys - Project created, deleted, renamed, moved (transferred), changed path @@ -182,24 +189,9 @@ From there, you can see the following actions: - Project was scheduled for deletion due to inactivity ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85689) in GitLab 15.0) - Project had a security policy project linked, changed, or unlinked ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6) -Project events can also be accessed via the [Project Audit Events API](../api/audit_events.md#project-audit-events). - -Project event queries are limited to a maximum of 30 days. - ### Instance events **(PREMIUM SELF)** -Server-wide audit events introduce the ability to observe user actions across -the entire instance of your GitLab server, making it easy to understand who -changed what and when for audit purposes. - -Instance events do not include group or project audit events. - -To view the server-wide audit events: - -1. On the top bar, select **Main menu > Admin**. -1. On the left sidebar, select **Monitoring > Audit Events**. - -The following user actions are recorded: +The following user actions on a GitLab instance generate instance audit events: - Sign-in events and the authentication type (such as standard, LDAP, or OmniAuth) - Failed sign-ins diff --git a/doc/architecture/blueprints/ci_pipeline_components/index.md b/doc/architecture/blueprints/ci_pipeline_components/index.md index e8fbc15a376..f98a82dfe5b 100644 --- a/doc/architecture/blueprints/ci_pipeline_components/index.md +++ b/doc/architecture/blueprints/ci_pipeline_components/index.md @@ -3,7 +3,7 @@ status: proposed creation-date: "2022-09-14" authors: [ "@fabio", "@grzesiek" ] coach: "@kamil" -approvers: [ "@dov" ] +approvers: [ "@dhershkovitch" ] owning-stage: "~devops::verify" participating-stages: [] --- diff --git a/doc/development/caching.md b/doc/development/caching.md index 36fbfc7010e..4c91e8eba6e 100644 --- a/doc/development/caching.md +++ b/doc/development/caching.md @@ -166,7 +166,7 @@ Is the cache being added "worthy"? This can be hard to measure, but you can cons - Calling the same method multiple times but only calculating the value once. - Stored in Ruby memory. - `@article ||= Article.find(params[:id])` - - `strong_memoize { Article.find(params[:id]) }` + - `strong_memoize_attr :method_name` 1. Request caching: - Return the same value for a key for the duration of a web request. - `Gitlab::SafeRequestStore.fetch` @@ -252,7 +252,7 @@ All the time! ### When to use method caching -- Using instance variables, or [strong_memoize](utilities.md#strongmemoize) is something we all tend to do anyway. +- Use instance variables, or [`StrongMemoize`](utilities.md#strongmemoize). - Useful when the same value is needed multiple times in a request. - Can be used to prevent multiple cache calls for the same key. - Can cause issues with ActiveRecord objects where a value doesn't change until you call diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md index e99926663dd..0dc950cbc4c 100644 --- a/doc/development/secure_coding_guidelines.md +++ b/doc/development/secure_coding_guidelines.md @@ -718,13 +718,12 @@ There are some cases where `users` passed in the code is actually referring to a ```ruby def find_user_from_sources - strong_memoize(:find_user_from_sources) do - deploy_token_from_request || - find_user_from_bearer_token || - find_user_from_job_token || - user_from_warden - end + deploy_token_from_request || + find_user_from_bearer_token || + find_user_from_job_token || + user_from_warden end + strong_memoize_attr :find_user_from_sources ``` ### Past Vulnerable Code diff --git a/doc/development/utilities.md b/doc/development/utilities.md index 551834670b3..a7f0500fd71 100644 --- a/doc/development/utilities.md +++ b/doc/development/utilities.md @@ -176,20 +176,6 @@ Refer to [`strong_memoize.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/maste You could write it like: - ```ruby - class Find - include Gitlab::Utils::StrongMemoize - - def result - strong_memoize(:result) do - search - end - end - end - ``` - - Alternatively, use the `strong_memoize_attr` helper to memoize the method for you: - ```ruby class Find include Gitlab::Utils::StrongMemoize diff --git a/doc/update/index.md b/doc/update/index.md index e810c63a7ea..31df17c4138 100644 --- a/doc/update/index.md +++ b/doc/update/index.md @@ -565,6 +565,8 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap than `/`. - [Incorrect deletion of object storage files on Geo secondary sites](https://gitlab.com/gitlab-org/gitlab/-/issues/371397) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532). - The `FF_GITLAB_REGISTRY_HELPER_IMAGE` [feature flag](../administration/feature_flags.md#enable-or-disable-the-feature) is removed and helper images are always pulled from GitLab Registry. +- The `AES256-GCM-SHA384` SSL cipher is no longer allowed by NGINX. + See how you can [add the cipher back](https://docs.gitlab.com/omnibus/update/gitlab_15_changes.html#aes256-gcm-sha384-ssl-cipher-no-longer-allowed-by-default-by-nginx) to the allow list. ### 14.10.0 diff --git a/lib/gitlab/memory/reports/heap_dump.rb b/lib/gitlab/memory/reports/heap_dump.rb new file mode 100644 index 00000000000..b81464ed5cf --- /dev/null +++ b/lib/gitlab/memory/reports/heap_dump.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Gitlab + module Memory + module Reports + class HeapDump + class << self + def enqueue! + log_event('enqueue') + @write_heap_dump = true + end + + # This is a no-op currently and will be implemented at a later time in + # https://gitlab.com/gitlab-org/gitlab/-/issues/370077 + def write_conditionally + return false unless enqueued? + + log_event('write') + + true + end + + private + + def enqueued? + !!@write_heap_dump + end + + def log_event(message) + Gitlab::AppLogger.info( + message: message, + pid: $$, + worker_id: worker_id, + perf_report: 'heap_dump' + ) + end + + def worker_id + ::Prometheus::PidProvider.worker_id + end + end + end + end + end +end diff --git a/lib/gitlab/memory/watchdog.rb b/lib/gitlab/memory/watchdog.rb index 19dfc640b5d..435b416e7e9 100644 --- a/lib/gitlab/memory/watchdog.rb +++ b/lib/gitlab/memory/watchdog.rb @@ -55,16 +55,8 @@ module Gitlab end ## - # Configuration for Watchdog, use like: - # - # watchdog.configure do |config| - # config.handler = Gitlab::Memory::Watchdog::TermProcessHandler - # config.sleep_time_seconds = 60 - # config.logger = Gitlab::AppLogger - # config.monitors do |stack| - # stack.push MyMonitorClass, args*, max_strikes:, kwargs**, &block - # end - # end + # Configuration for Watchdog, see Gitlab::Memory::Watchdog::Configurator + # for examples. def configure yield @configuration end @@ -106,6 +98,8 @@ module Gitlab logger.warn(all_labels) @counter_violations_handled.increment(reason: monitor_name) + Gitlab::Memory::Reports::HeapDump.enqueue! if @configuration.write_heap_dumps? + handler.call end diff --git a/lib/gitlab/memory/watchdog/configuration.rb b/lib/gitlab/memory/watchdog/configuration.rb index 793f75adf59..4bad9475531 100644 --- a/lib/gitlab/memory/watchdog/configuration.rb +++ b/lib/gitlab/memory/watchdog/configuration.rb @@ -39,7 +39,7 @@ module Gitlab DEFAULT_SLEEP_TIME_SECONDS = 60 - attr_writer :logger, :handler, :sleep_time_seconds + attr_writer :logger, :handler, :sleep_time_seconds, :write_heap_dumps def monitors @monitor_stack ||= MonitorStack.new @@ -59,6 +59,10 @@ module Gitlab def sleep_time_seconds @sleep_time_seconds ||= DEFAULT_SLEEP_TIME_SECONDS end + + def write_heap_dumps? + !!@write_heap_dumps + end end end end diff --git a/lib/gitlab/memory/watchdog/configurator.rb b/lib/gitlab/memory/watchdog/configurator.rb index 6d6f97dc8ba..da3733731a7 100644 --- a/lib/gitlab/memory/watchdog/configurator.rb +++ b/lib/gitlab/memory/watchdog/configurator.rb @@ -7,26 +7,32 @@ module Gitlab class << self def configure_for_puma lambda do |config| - sleep_time_seconds = ENV.fetch('GITLAB_MEMWD_SLEEP_TIME_SEC', 60).to_i config.logger = Gitlab::AppLogger config.handler = Gitlab::Memory::Watchdog::PumaHandler.new - config.sleep_time_seconds = sleep_time_seconds + config.write_heap_dumps = write_heap_dumps? + config.sleep_time_seconds = ENV.fetch('GITLAB_MEMWD_SLEEP_TIME_SEC', 60).to_i config.monitors(&configure_monitors_for_puma) end end def configure_for_sidekiq lambda do |config| - sleep_time_seconds = [ENV.fetch('SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL', 3).to_i, 2].max config.logger = Sidekiq.logger config.handler = Gitlab::Memory::Watchdog::TermProcessHandler.new - config.sleep_time_seconds = sleep_time_seconds + config.write_heap_dumps = write_heap_dumps? + config.sleep_time_seconds = [ + ENV.fetch('SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL', 3).to_i, 2 + ].max config.monitors(&configure_monitors_for_sidekiq) end end private + def write_heap_dumps? + Gitlab::Utils.to_boolean(ENV['GITLAB_MEMWD_DUMP_HEAP'], default: false) + end + def configure_monitors_for_puma lambda do |stack| max_strikes = ENV.fetch('GITLAB_MEMWD_MAX_STRIKES', 5).to_i diff --git a/lib/gitlab/utils/strong_memoize.rb b/lib/gitlab/utils/strong_memoize.rb index 6456ad08924..306180ded6a 100644 --- a/lib/gitlab/utils/strong_memoize.rb +++ b/lib/gitlab/utils/strong_memoize.rb @@ -16,16 +16,6 @@ module Gitlab # include Gitlab::Utils::StrongMemoize # # def trigger_from_token - # strong_memoize(:trigger) do - # Ci::Trigger.find_by_token(params[:token].to_s) - # end - # end - # - # Or like: - # - # include Gitlab::Utils::StrongMemoize - # - # def trigger_from_token # Ci::Trigger.find_by_token(params[:token].to_s) # end # strong_memoize_attr :trigger_from_token diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5d7d8c15904..4e76c16d295 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -13591,6 +13591,9 @@ msgstr "" msgid "DeploymentApproval|Rejected by you %{time}" msgstr "" +msgid "DeploymentTarget|Edge Computing (e.g. Cloudflare Workers)" +msgstr "" + msgid "DeploymentTarget|GitLab Pages" msgstr "" @@ -13627,6 +13630,9 @@ msgstr "" msgid "DeploymentTarget|Virtual machine (for example, EC2)" msgstr "" +msgid "DeploymentTarget|Web Deployment Platform (Netlify, Vercel, Gatsby)" +msgstr "" + msgid "Deployments" msgstr "" @@ -23815,15 +23821,18 @@ msgstr "" msgid "Labels" msgstr "" -msgid "Labels can be applied to %{features}. Group labels are available for any project within the group." -msgstr "" - msgid "Labels can be applied to issues and merge requests to categorize them." msgstr "" +msgid "Labels can be applied to issues and merge requests. Group labels are available for any project within the group." +msgstr "" + msgid "Labels can be applied to issues and merge requests. Star a label to make it a priority label." msgstr "" +msgid "Labels can be applied to issues, merge requests, and epics. Group labels are available for any project within the group." +msgstr "" + msgid "Labels with no issues in this iteration:" msgstr "" diff --git a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb index b344e5f7b1f..449bffe61e0 100644 --- a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb @@ -1,7 +1,15 @@ # frozen_string_literal: true module QA - RSpec.describe 'Create', :gitlab_pages, :orchestrated, except: { job: 'review-qa-*' } do + RSpec.describe 'Create', + :gitlab_pages, + :orchestrated, + except: { job: 'review-qa-*' }, + quarantine: { + issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/383215', + type: :test_environment, + only: { subdomain: 'staging-ref' } + } do # TODO: Convert back to :smoke once proved to be stable. Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/300906 describe 'Pages', product_group: :editor do let!(:project) do diff --git a/rubocop/cop/gitlab/strong_memoize_attr.rb b/rubocop/cop/gitlab/strong_memoize_attr.rb new file mode 100644 index 00000000000..2da7f71b920 --- /dev/null +++ b/rubocop/cop/gitlab/strong_memoize_attr.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Gitlab + # Cop that disallows functions that contain only a call to `strong_memoize()`, in favor + # of `strong_memoize_attr()`. + class StrongMemoizeAttr < RuboCop::Cop::Base + extend RuboCop::Cop::AutoCorrector + + MSG = 'Use `strong_memoize_attr`, instead of using `strong_memoize` directly' + + def_node_matcher :strong_memoize?, <<~PATTERN + (def $_ _ + (block + $(send nil? :strong_memoize + (sym $_) + ) + (args) + $_ + ) + ) + PATTERN + + def on_def(node) + method_name, send_node, attr_name, body = strong_memoize?(node) + return unless method_name + + add_offense(send_node) do |corrector| + attr_suffix = ", :#{attr_name}" if attr_name != method_name + + corrector.insert_after(node, "\n#{indent(node)}strong_memoize_attr :#{method_name}#{attr_suffix}") + corrector.replace(node.body, body.source) + end + end + end + end + end +end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 446e5e38865..f80feed6c33 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -702,16 +702,12 @@ RSpec.describe ProjectsController do skip unless project.hashed_storage?(:repository) hashed_storage_path = ::Storage::Hashed.new(project).disk_path - original_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - project.repository.path - end + original_repository_path = project.repository.relative_path expect { update_project path: 'renamed_path' }.to change { project.reload.path } expect(project.path).to include 'renamed_path' - assign_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - assigns(:repository).path - end + assign_repository_path = assigns(:repository).relative_path expect(original_repository_path).to include(hashed_storage_path) expect(assign_repository_path).to include(hashed_storage_path) @@ -721,16 +717,12 @@ RSpec.describe ProjectsController do skip if project.hashed_storage?(:repository) hashed_storage_path = Storage::Hashed.new(project).disk_path - original_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - project.repository.path - end + original_repository_path = project.repository.relative_path expect { update_project path: 'renamed_path' }.to change { project.reload.path } expect(project.path).to include 'renamed_path' - assign_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do - assigns(:repository).path - end + assign_repository_path = assigns(:repository).relative_path expect(original_repository_path).not_to include(hashed_storage_path) expect(assign_repository_path).to include(hashed_storage_path) diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 85420d4afda..e8e981251e3 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -321,4 +321,27 @@ RSpec.describe LabelsHelper do expect(wrap_label_html('xss', label: xss_label, small: false)).not_to include('color:') end end + + describe '#label_subscription_toggle_button_text' do + let(:label) { instance_double(Label) } + let(:current_user) { instance_double(User) } + + subject { label_subscription_toggle_button_text(label) } + + context 'when the label is subscribed' do + before do + allow(label).to receive(:subscribed?).and_return(true) + end + + it { is_expected.to eq(_('Unsubscribe')) } + end + + context 'when the label is not subscribed' do + before do + allow(label).to receive(:subscribed?).and_return(false) + end + + it { is_expected.to eq(_('Subscribe')) } + end + end end diff --git a/spec/initializers/diagnostic_reports_spec.rb b/spec/initializers/diagnostic_reports_spec.rb index 01b1ed9b7b5..2022076072b 100644 --- a/spec/initializers/diagnostic_reports_spec.rb +++ b/spec/initializers/diagnostic_reports_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'diagnostic reports' do shared_examples 'does not modify worker startup hooks' do it do expect(Gitlab::Cluster::LifecycleEvents).not_to receive(:on_worker_start) + expect(Gitlab::Cluster::LifecycleEvents).not_to receive(:on_worker_stop) expect(Gitlab::Memory::ReportsDaemon).not_to receive(:instance) load_initializer @@ -30,19 +31,23 @@ RSpec.describe 'diagnostic reports' do it 'modifies worker startup hooks, starts Gitlab::Memory::ReportsDaemon' do expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_start).and_call_original - + expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_stop) expect_next_instance_of(Gitlab::Memory::ReportsDaemon) do |daemon| - expect(daemon).to receive(:start).and_call_original - - # make sleep no-op - allow(daemon).to receive(:sleep).and_return(nil) - - # let alive return 3 times: true, true, false - allow(daemon).to receive(:alive).and_return(true, true, false) + expect(daemon).to receive(:start) end load_initializer end + + it 'writes scheduled heap dumps in on_worker_stop' do + expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_start) + expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_stop).and_call_original + expect(Gitlab::Memory::Reports::HeapDump).to receive(:write_conditionally) + + load_initializer + # This is necessary because this hook normally fires during worker shutdown. + Gitlab::Cluster::LifecycleEvents.do_worker_stop + end end context 'when run in non-Puma context, such as rails console, tests, Sidekiq' do diff --git a/spec/lib/gitlab/memory/reports/heap_dump_spec.rb b/spec/lib/gitlab/memory/reports/heap_dump_spec.rb new file mode 100644 index 00000000000..2532b8c5295 --- /dev/null +++ b/spec/lib/gitlab/memory/reports/heap_dump_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Memory::Reports::HeapDump do + describe '.write_conditionally' do + subject(:call) { described_class.write_conditionally } + + context 'when no heap dump is enqueued' do + it 'does nothing and returns false' do + expect(call).to be(false) + end + end + + context 'when a heap dump is enqueued' do + it 'does nothing and returns true' do + described_class.enqueue! + + expect(call).to be(true) + end + end + end +end diff --git a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb index e6f2d57e9e6..0d3a6eab48c 100644 --- a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb +++ b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb @@ -19,6 +19,12 @@ RSpec.describe Gitlab::Memory::Watchdog::Configurator do expect(configuration.logger).to eq(logger) end + it 'does not enable writing heap dumps by default' do + configurator.call(configuration) + + expect(configuration.write_heap_dumps?).to be(false) + end + context 'when sleep_time_seconds is not passed through the environment' do let(:sleep_time_seconds) { sleep_time } @@ -42,6 +48,42 @@ RSpec.describe Gitlab::Memory::Watchdog::Configurator do expect(configuration.sleep_time_seconds).to eq(sleep_time_seconds) end end + + context 'when GITLAB_MEMWD_DUMP_HEAP is set' do + before do + stub_env('GITLAB_MEMWD_DUMP_HEAP', env_var) + end + + context 'with null value' do + let(:env_var) { nil } + + it 'does not enable writing heap dumps' do + configurator.call(configuration) + + expect(configuration.write_heap_dumps?).to be(false) + end + end + + context 'with falsey value' do + let(:env_var) { '0' } + + it 'does not enable writing heap dumps' do + configurator.call(configuration) + + expect(configuration.write_heap_dumps?).to be(false) + end + end + + context 'with truthy value' do + let(:env_var) { '1' } + + it 'enables writing heap dumps' do + configurator.call(configuration) + + expect(configuration.write_heap_dumps?).to be(true) + end + end + end end shared_examples 'as monitor configurator' do diff --git a/spec/lib/gitlab/memory/watchdog_spec.rb b/spec/lib/gitlab/memory/watchdog_spec.rb index 5d9599d6eab..8703bf8b00b 100644 --- a/spec/lib/gitlab/memory/watchdog_spec.rb +++ b/spec/lib/gitlab/memory/watchdog_spec.rb @@ -8,6 +8,7 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do let(:handler) { instance_double(described_class::NullHandler) } let(:logger) { instance_double(::Logger) } let(:sleep_time_seconds) { 60 } + let(:write_heap_dumps) { false } let(:threshold_violated) { false } let(:violations_counter) { instance_double(::Prometheus::Client::Counter) } let(:violations_handled_counter) { instance_double(::Prometheus::Client::Counter) } @@ -69,6 +70,7 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do config.handler = handler config.logger = logger config.sleep_time_seconds = sleep_time_seconds + config.write_heap_dumps = write_heap_dumps config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes end @@ -154,6 +156,16 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do watchdog.call end + + context 'and heap dumps are enabled' do + let(:write_heap_dumps) { true } + + it 'does not schedule a heap dump' do + expect(Gitlab::Memory::Reports::HeapDump).not_to receive(:enqueue!) + + watchdog.call + end + end end context 'when monitor exceeds the allowed number of strikes' do @@ -186,6 +198,16 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do watchdog.call end + context 'and heap dumps are enabled' do + let(:write_heap_dumps) { true } + + it 'schedules a heap dump' do + expect(Gitlab::Memory::Reports::HeapDump).to receive(:enqueue!) + + watchdog.call + end + end + context 'when enforce_memory_watchdog ops toggle is off' do before do stub_feature_flags(enforce_memory_watchdog: false) @@ -255,6 +277,10 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do subject(:handler) { described_class::TermProcessHandler.new(42) } describe '#call' do + before do + allow(Process).to receive(:kill) + end + it 'sends SIGTERM to the current process' do expect(Process).to receive(:kill).with(:TERM, 42) @@ -274,11 +300,12 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do before do stub_const('::Puma::Cluster::WorkerHandle', puma_worker_handle_class) + allow(puma_worker_handle_class).to receive(:new).and_return(puma_worker_handle) + allow(puma_worker_handle).to receive(:term) end describe '#call' do it 'invokes orderly termination via Puma API' do - expect(puma_worker_handle_class).to receive(:new).and_return(puma_worker_handle) expect(puma_worker_handle).to receive(:term) expect(handler.call).to be(true) diff --git a/spec/lib/gitlab/utils/strong_memoize_spec.rb b/spec/lib/gitlab/utils/strong_memoize_spec.rb index 236b6d29ba7..6a09a8da58e 100644 --- a/spec/lib/gitlab/utils/strong_memoize_spec.rb +++ b/spec/lib/gitlab/utils/strong_memoize_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Gitlab::Utils::StrongMemoize do end def method_name - strong_memoize(:method_name) do + strong_memoize(:method_name) do # rubocop: disable Gitlab/StrongMemoizeAttr trace << value value end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index aea8bdaf343..a4c52714458 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -25,7 +25,7 @@ RSpec.describe Issue do it { is_expected.to have_many(:design_versions) } it { is_expected.to have_one(:sentry_issue) } it { is_expected.to have_one(:alert_management_alert) } - it { is_expected.to have_many(:alert_management_alerts) } + it { is_expected.to have_many(:alert_management_alerts).validate(false) } it { is_expected.to have_many(:resource_milestone_events) } it { is_expected.to have_many(:resource_state_events) } it { is_expected.to have_and_belong_to_many(:prometheus_alert_events) } diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index 214165cb171..14ca2e439bf 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -360,7 +360,7 @@ RSpec.describe 'getting an issue list for a project' do post_graphql(query, current_user: current_user) alert_titles = issues_data.map { |issue| issue.dig('alertManagementAlert', 'title') } - expected_titles = issues.map { |issue| issue.alert_management_alert&.title } + expected_titles = issues.map { |issue| issue.alert_management_alerts.first&.title } expect(alert_titles).to contain_exactly(*expected_titles) end diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb index 613732c19ea..ff66023e37d 100644 --- a/spec/requests/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -6,6 +6,7 @@ RSpec.describe SearchController, type: :request do let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project, :public, :repository, :wiki_repo, name: 'awesome project', group: group) } + let_it_be(:projects) { create_list(:project, 5, :public, :repository, :wiki_repo) } before do login_as(user) @@ -20,9 +21,16 @@ RSpec.describe SearchController, type: :request do create(object, *creation_traits, creation_args) control = ActiveRecord::QueryRecorder.new(skip_cached: false) { send_search_request(params) } - create_list(object, 3, *creation_traits, creation_args) + expect(response.body).to include('search-results') # Confirm there are search results to prevent false positives + + projects.each do |project| + creation_args[:source_project] = project if creation_args.key?(:source_project) + creation_args[:project] = project if creation_args.key?(:project) + create(object, *creation_traits, creation_args) + end expect { send_search_request(params) }.not_to exceed_all_query_limit(control).with_threshold(threshold) + expect(response.body).to include('search-results') # Confirm there are search results to prevent false positives end end @@ -33,26 +41,26 @@ RSpec.describe SearchController, type: :request do let(:object) { :issue } let(:creation_args) { { project: project, title: 'foo' } } let(:params) { { search: 'foo', scope: 'issues' } } - # there are 4 additional queries run for the logged in user: - # (1) geo_nodes, (1) users, (2) broadcast_messages - let(:threshold) { 4 } + # some N+1 queries still exist + # each issue runs an extra query for group namespaces + let(:threshold) { 1 } it_behaves_like 'an efficient database result' end - context 'for merge_request scope' do + context 'for merge_requests scope' do let(:creation_traits) { [:unique_branches] } let(:object) { :merge_request } let(:creation_args) { { source_project: project, title: 'bar' } } let(:params) { { search: 'bar', scope: 'merge_requests' } } - # there are 4 additional queries run for the logged in user: - # - (1) geo_nodes, (1) users, (2) broadcast_messages + # some N+1 queries still exist + # each merge request runs an extra query for project routes let(:threshold) { 4 } it_behaves_like 'an efficient database result' end - context 'for project scope' do + context 'for projects scope' do let(:creation_traits) { [:public] } let(:object) { :project } let(:creation_args) { { name: 'project' } } @@ -63,12 +71,67 @@ RSpec.describe SearchController, type: :request do # - one count for open MRs # - one count for open Issues # there are 4 additional queries run for the logged in user: - # (1) geo_nodes, (1) users, (2) broadcast_messages - let(:threshold) { 13 } + # (1) user preferences, (1) user statuses, (1) user details, (1) users + let(:threshold) { 17 } it_behaves_like 'an efficient database result' end + context 'for milestones scope' do + let(:object) { :milestone } + let(:creation_args) { { project: project } } + let(:params) { { search: 'title', scope: 'milestones' } } + let(:threshold) { 0 } + + it_behaves_like 'an efficient database result' + end + + context 'for users scope' do + let(:object) { :user } + let(:creation_args) { { name: 'georgia' } } + let(:params) { { search: 'georgia', scope: 'users' } } + let(:threshold) { 0 } + + it_behaves_like 'an efficient database result' + end + + context 'for notes scope' do + let(:creation_traits) { [:on_commit] } + let(:object) { :note } + let(:creation_args) { { project: project, note: 'hello world' } } + let(:params) { { search: 'hello world', scope: 'notes', project_id: project.id } } + let(:threshold) { 0 } + + it_behaves_like 'an efficient database result' + end + + context 'for blobs scope' do + # blobs are enabled for project search only in basic search + let(:params_for_one) { { search: 'test', project_id: project.id, scope: 'blobs', per_page: 1 } } + let(:params_for_many) { { search: 'test', project_id: project.id, scope: 'blobs', per_page: 5 } } + + it 'avoids N+1 database queries' do + control = ActiveRecord::QueryRecorder.new { send_search_request(params_for_one) } + expect(response.body).to include('search-results') # Confirm search results to prevent false positives + + expect { send_search_request(params_for_many) }.not_to exceed_query_limit(control.count) + expect(response.body).to include('search-results') # Confirm search results to prevent false positives + end + end + + context 'for commits scope' do + let(:params_for_one) { { search: 'test', project_id: project.id, scope: 'commits', per_page: 1 } } + let(:params_for_many) { { search: 'test', project_id: project.id, scope: 'commits', per_page: 5 } } + + it 'avoids N+1 database queries' do + control = ActiveRecord::QueryRecorder.new { send_search_request(params_for_one) } + expect(response.body).to include('search-results') # Confirm search results to prevent false positives + + expect { send_search_request(params_for_many) }.not_to exceed_query_limit(control.count) + expect(response.body).to include('search-results') # Confirm search results to prevent false positives + end + end + context 'when searching by SHA' do let(:sha) { '6d394385cf567f80a8fd85055db1ab4c5295806f' } diff --git a/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb new file mode 100644 index 00000000000..20dd0f89f53 --- /dev/null +++ b/spec/rubocop/cop/gitlab/strong_memoize_attr_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require_relative '../../../../rubocop/cop/gitlab/strong_memoize_attr' + +RSpec.describe RuboCop::Cop::Gitlab::StrongMemoizeAttr do + context 'when strong_memoize() is the entire body of a method' do + context 'when the memoization name is the same as the method name' do + it 'registers an offense and autocorrects' do + expect_offense(<<~RUBY) + class Foo + def memoized_method + strong_memoize(:memoized_method) do + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize` directly + 'This is a memoized method' + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo + def memoized_method + 'This is a memoized method' + end + strong_memoize_attr :memoized_method + end + RUBY + end + end + + context 'when the memoization name is different from the method name' do + it 'registers an offense and autocorrects' do + expect_offense(<<~RUBY) + class Foo + def enabled? + strong_memoize(:enabled) do + ^^^^^^^^^^^^^^^^^^^^^^^^ Use `strong_memoize_attr`, instead of using `strong_memoize` directly + true + end + end + end + RUBY + + expect_correction(<<~RUBY) + class Foo + def enabled? + true + end + strong_memoize_attr :enabled?, :enabled + end + RUBY + end + end + end + + context 'when strong_memoize() is not the entire body of the method' do + it 'does not register an offense or autocorrect' do + expect_no_offenses(<<~RUBY) + class Foo + def memoized_method + msg = 'This is a memoized method' + + strong_memoize(:memoized_method) do + msg + end + end + end + RUBY + end + end +end diff --git a/spec/services/incident_management/incidents/create_service_spec.rb b/spec/services/incident_management/incidents/create_service_spec.rb index 851b21e1227..7db762b9c5b 100644 --- a/spec/services/incident_management/incidents/create_service_spec.rb +++ b/spec/services/incident_management/incidents/create_service_spec.rb @@ -66,6 +66,26 @@ RSpec.describe IncidentManagement::Incidents::CreateService do end end end + + context 'with an alert' do + subject(:create_incident) { described_class.new(project, user, title: title, description: description, alert: alert).execute } + + context 'when the alert is valid' do + let(:alert) { create(:alert_management_alert, project: project) } + + it 'associates the alert with the incident' do + expect(create_incident[:issue].reload.alert_management_alerts).to match_array([alert]) + end + end + + context 'when the alert is not valid' do + let(:alert) { create(:alert_management_alert, :with_validation_errors, project: project) } + + it 'does not associate the alert with the incident' do + expect(create_incident[:issue].reload.alert_management_alerts).to be_empty + end + end + end end context 'when incident has no title' do @@ -89,10 +109,6 @@ RSpec.describe IncidentManagement::Incidents::CreateService do subject(:create_incident) { described_class.new(project, user, title: title, description: description, alert: alert).execute } - it 'associates the alert with the incident' do - expect(create_incident[:issue].alert_management_alert).to eq(alert) - end - context 'the alert prevents the issue from saving' do let(:alert) { create(:alert_management_alert, :with_validation_errors, project: project) } diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index ef92b6984d5..dcb17c95f3b 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -346,31 +346,29 @@ RSpec.describe Issues::CloseService do context 'when there is an associated Alert Management Alert' do context 'when alert can be resolved' do - let!(:alert) { create(:alert_management_alert, issue: issue, project: project) } - it 'resolves an alert and sends a system note' do + alert = create(:alert_management_alert, issue: issue, project: project) + expect_any_instance_of(SystemNoteService) do |notes_service| expect(notes_service).to receive(:change_alert_status).with( - alert, - current_user, - " by closing issue #{issue.to_reference(project)}" + alert, current_user, " by closing issue #{issue.to_reference(project)}" ) end close_issue - expect(alert.reload.resolved?).to eq(true) + expect(alert.reload).to be_resolved end end context 'when alert cannot be resolved' do - let!(:alert) { create(:alert_management_alert, :with_validation_errors, issue: issue, project: project) } - before do allow(Gitlab::AppLogger).to receive(:warn).and_call_original end it 'writes a warning into the log' do + alert = create(:alert_management_alert, :with_validation_errors, issue: issue, project: project) + close_issue expect(Gitlab::AppLogger).to have_received(:warn).with( @@ -383,6 +381,26 @@ RSpec.describe Issues::CloseService do end end + context 'when there are several associated Alert Management Alerts' do + context 'when alerts can be resolved' do + it 'resolves an alert and sends a system note', :aggregate_failures do + alerts = create_list(:alert_management_alert, 2, issue: issue, project: project) + + alerts.each do |alert| + expect_any_instance_of(SystemNoteService) do |notes_service| + expect(notes_service).to receive(:change_alert_status).with( + alert, current_user, " by closing issue #{issue.to_reference(project)}" + ) + end + end + + close_issue + + expect(alerts.map(&:reload)).to all(be_resolved) + end + end + end + it 'deletes milestone issue counters cache' do issue.update!(milestone: create(:milestone, project: project)) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 8f505c31c5a..7fd8ab555f7 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -263,7 +263,7 @@ RSpec.describe Projects::TransferService do end context 'when transfer fails' do - let!(:original_path) { project_path(project) } + let!(:original_path) { project.repository.relative_path } def attempt_project_transfer(&block) expect do @@ -277,21 +277,11 @@ RSpec.describe Projects::TransferService do expect_any_instance_of(Labels::TransferService).to receive(:execute).and_raise(ActiveRecord::StatementInvalid, "PG ERROR") end - def project_path(project) - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - project.repository.path_to_repo - end - end - - def current_path - project_path(project) - end - it 'rolls back repo location' do attempt_project_transfer expect(project.repository.raw.exists?).to be(true) - expect(original_path).to eq current_path + expect(original_path).to eq project.repository.relative_path end it 'rolls back project full path in gitaly' do diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb index 7d0f8c09933..eab30be9243 100644 --- a/spec/support/helpers/search_helpers.rb +++ b/spec/support/helpers/search_helpers.rb @@ -35,6 +35,8 @@ module SearchHelpers def select_search_scope(scope) page.within '[data-testid="search-filter"]' do click_link scope + + wait_for_all_requests end end diff --git a/spec/views/search/_results.html.haml_spec.rb b/spec/views/search/_results.html.haml_spec.rb index 2149c394320..e81462ee518 100644 --- a/spec/views/search/_results.html.haml_spec.rb +++ b/spec/views/search/_results.html.haml_spec.rb @@ -3,36 +3,60 @@ require 'spec_helper' RSpec.describe 'search/_results' do - let(:user) { create(:user) } + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + let(:search_objects) { Issue.page(1).per(2) } let(:scope) { 'issues' } let(:term) { 'foo' } + let(:search_results) { instance_double('Gitlab::SearchResults', { formatted_count: 10, current_user: user } ) } + let(:search_service) { class_double(SearchServicePresenter, scope: scope, search: term, current_user: user) } before do controller.params[:action] = 'show' controller.params[:search] = term - allow(self).to receive(:current_user).and_return(user) - allow(@search_results).to receive(:formatted_count).with(scope).and_return(10) - allow(self).to receive(:search_count_path).with(any_args).and_return("test count link") - allow(self).to receive(:search_path).with(any_args).and_return("link test") - - stub_feature_flags(search_page_vertical_nav: false) - create_list(:issue, 3) - @search_objects = search_objects - @scope = scope - @search_term = term - @search_service = SearchServicePresenter.new(SearchService.new(user, search: term, scope: scope)) + allow(view).to receive(:current_user) { user } + assign(:search_count_path, 'test count link') + assign(:search_path, 'link test') + assign(:search_results, search_results) + assign(:search_objects, search_objects) + assign(:search_term, term) + assign(:scope, scope) + @search_service = SearchServicePresenter.new(SearchService.new(user, search: term, scope: scope)) allow(@search_service).to receive(:search_objects).and_return(search_objects) end - it 'displays the page size' do - render + where(search_page_vertical_nav_enabled: [true, false]) - expect(rendered).to have_content('Showing 1 - 2 of 3 issues for foo') + with_them do + describe 'page size' do + before do + stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled) + end + + context 'when search results have a count' do + it 'displays the page size' do + render + + expect(rendered).to have_content('Showing 1 - 2 of 3 issues for foo') + end + end + + context 'when search results do not have a count' do + let(:search_objects) { Issue.page(1).per(2).without_count } + + it 'does not display the page size' do + render + + expect(rendered).not_to have_content(/Showing .* of .*/) + end + end + end end context 'when searching notes which contain quotes in markdown' do @@ -51,18 +75,6 @@ RSpec.describe 'search/_results' do end end - context 'when search results do not have a count' do - before do - @search_objects = @search_objects.without_count - end - - it 'does not display the page size' do - render - - expect(rendered).not_to have_content(/Showing .* of .*/) - end - end - context 'rendering all types of search results' do let_it_be(:project) { create(:project, :repository, :wiki_repo) } let_it_be(:issue) { create(:issue, project: project, title: 'testing') }