diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-21 18:12:22 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-21 18:12:22 +0300 |
commit | 5dc70663c4ff1feb215428ce50673b5b646f9809 (patch) | |
tree | 944bde8a8350ac8ee64335cc5b98d1c60ba9c3c5 | |
parent | fbc1f4ffc29ae99f438b07872c3c00fbe7651caa (diff) |
Add latest changes from gitlab-org/gitlab@master
39 files changed, 1293 insertions, 193 deletions
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. -## List of events +## View audit events -There are two kinds of events logged: +Depending on the events you want to view, at a minimum you must have: -- 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. +- 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. -NOTE: -Some events are recorded and available only as [streaming audit events](audit_event_streaming.md). +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 + +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 @@ -181,20 +181,6 @@ Refer to [`strong_memoize.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/maste 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 - - def result search end strong_memoize_attr :result 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 `<custom_hooks_dir>/<hook_name>`. - [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." +msgid "Labels can be applied to issues and merge requests to categorize them." msgstr "" -msgid "Labels can be applied to issues and merge requests to categorize them." +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,18 +31,22 @@ 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 + expect(daemon).to receive(:start) + end - # make sleep no-op - allow(daemon).to receive(:sleep).and_return(nil) + load_initializer + end - # let alive return 3 times: true, true, false - allow(daemon).to receive(:alive).and_return(true, true, false) - 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 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]) + + 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).to have_content('Showing 1 - 2 of 3 issues for foo') + 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') } |