summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:08:38 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-20 15:08:38 +0000
commit93b6ee78bf98cbc42712b7c5486ab0e78adb339f (patch)
tree29efc441f06368d2ec05196fcba070ee37c765b7
parent96add3eb957ee4256910087070e27850dd61cfe9 (diff)
downloadgitlab-ce-93b6ee78bf98cbc42712b7c5486ab0e78adb339f.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/rspec/expect_in_hook.yml54
-rw-r--r--.rubocop_todo/rspec/return_from_stub.yml12
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue6
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/models/deploy_key.rb4
-rw-r--r--app/services/system_note_service.rb12
-rw-r--r--app/services/system_notes/issuables_service.rb41
-rw-r--r--app/services/work_items/parent_links/create_service.rb4
-rw-r--r--app/services/work_items/parent_links/destroy_service.rb4
-rw-r--r--config/feature_flags/ops/report_jemalloc_stats.yml8
-rw-r--r--config/initializers/diagnostic_reports.rb11
-rw-r--r--doc/administration/geo/replication/docker_registry.md42
-rw-r--r--doc/user/analytics/index.md16
-rw-r--r--doc/user/group/iterations/index.md14
-rw-r--r--doc/user/project/milestones/index.md8
-rw-r--r--lib/gitlab/database/background_migration/batched_job.rb4
-rw-r--r--lib/gitlab/memory/jemalloc.rb16
-rw-r--r--lib/gitlab/memory/reports/jemalloc_stats.rb68
-rw-r--r--lib/gitlab/memory/reports_daemon.rb96
-rw-r--r--locale/gitlab.pot12
-rw-r--r--package.json2
-rw-r--r--spec/components/diffs/overflow_warning_component_spec.rb2
-rw-r--r--spec/components/diffs/stats_component_spec.rb2
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js14
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js2
-rw-r--r--spec/initializers/diagnostic_reports_spec.rb65
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_spec.rb21
-rw-r--r--spec/lib/gitlab/memory/jemalloc_spec.rb20
-rw-r--r--spec/lib/gitlab/memory/reports/jemalloc_stats_spec.rb134
-rw-r--r--spec/lib/gitlab/memory/reports_daemon_spec.rb121
-rw-r--r--spec/models/deploy_key_spec.rb6
-rw-r--r--spec/services/system_note_service_spec.rb34
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb39
-rw-r--r--spec/services/work_items/parent_links/create_service_spec.rb24
-rw-r--r--spec/services/work_items/parent_links/destroy_service_spec.rb9
-rw-r--r--spec/support/shared_examples/components/pajamas_shared_examples.rb4
-rw-r--r--yarn.lock8
40 files changed, 867 insertions, 84 deletions
diff --git a/.rubocop_todo/rspec/expect_in_hook.yml b/.rubocop_todo/rspec/expect_in_hook.yml
index cd73b76b14e..d138ea806f8 100644
--- a/.rubocop_todo/rspec/expect_in_hook.yml
+++ b/.rubocop_todo/rspec/expect_in_hook.yml
@@ -1,8 +1,5 @@
---
RSpec/ExpectInHook:
- # Offense count: 1074
- # Temporarily disabled due to too many offenses
- Enabled: false
Exclude:
- 'ee/spec/controllers/ee/projects/merge_requests/content_controller_spec.rb'
- 'ee/spec/controllers/groups/analytics/productivity_analytics_controller_spec.rb'
@@ -13,11 +10,15 @@ RSpec/ExpectInHook:
- 'ee/spec/controllers/registrations/groups_projects_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb'
- 'ee/spec/controllers/trials_controller_spec.rb'
+ - 'ee/spec/elastic/migrate/20220118150500_delete_orphaned_commits_spec.rb'
+ - 'ee/spec/elastic/migrate/20220119120500_populate_commit_permissions_in_main_index_spec.rb'
+ - 'ee/spec/features/billings/billing_plans_spec.rb'
- 'ee/spec/features/boards/new_issue_spec.rb'
- 'ee/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb'
- 'ee/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb'
- 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
- 'ee/spec/features/registrations/combined_registration_spec.rb'
+ - 'ee/spec/features/registrations/saas_user_registration_spec.rb'
- 'ee/spec/features/registrations/trial_during_signup_flow_spec.rb'
- 'ee/spec/features/signup_spec.rb'
- 'ee/spec/features/trial_registrations/company_information_spec.rb'
@@ -29,10 +30,14 @@ RSpec/ExpectInHook:
- 'ee/spec/graphql/mutations/gitlab_subscriptions/activate_spec.rb'
- 'ee/spec/helpers/billing_plans_helper_spec.rb'
- 'ee/spec/helpers/ee/ci/runners_helper_spec.rb'
+ - 'ee/spec/helpers/ee/groups_helper_spec.rb'
+ - 'ee/spec/helpers/ee/integrations_helper_spec.rb'
- 'ee/spec/helpers/ee/issues_helper_spec.rb'
+ - 'ee/spec/helpers/ee/projects/security/dast_configuration_helper_spec.rb'
- 'ee/spec/helpers/ee/welcome_helper_spec.rb'
- 'ee/spec/helpers/kerberos_spnego_helper_spec.rb'
- 'ee/spec/helpers/vulnerabilities_helper_spec.rb'
+ - 'ee/spec/lib/ee/api/helpers/members_helpers_spec.rb'
- 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
- 'ee/spec/lib/ee/gitlab/gon_helper_spec.rb'
- 'ee/spec/lib/ee/gitlab/hook_data/user_builder_spec.rb'
@@ -44,7 +49,6 @@ RSpec/ExpectInHook:
- 'ee/spec/lib/gitlab/geo_spec.rb'
- 'ee/spec/lib/gitlab/git_access_spec.rb'
- 'ee/spec/lib/gitlab/graphql/aggregations/epics/lazy_epic_aggregate_spec.rb'
- - 'ee/spec/lib/gitlab/graphql/aggregations/issues/lazy_links_aggregate_spec.rb'
- 'ee/spec/lib/gitlab/mirror_spec.rb'
- 'ee/spec/lib/gitlab/sitemaps/generator_spec.rb'
- 'ee/spec/lib/gitlab/subscription_portal/clients/graphql_spec.rb'
@@ -57,14 +61,15 @@ RSpec/ExpectInHook:
- 'ee/spec/models/concerns/geo/replicable_model_spec.rb'
- 'ee/spec/models/container_repository_spec.rb'
- 'ee/spec/models/dora/daily_metrics_spec.rb'
+ - 'ee/spec/models/ee/namespace/storage/notification_spec.rb'
- 'ee/spec/models/ee/namespace_spec.rb'
- 'ee/spec/models/gitlab_subscription_spec.rb'
- 'ee/spec/models/license_spec.rb'
+ - 'ee/spec/models/member_spec.rb'
- 'ee/spec/models/project_import_state_spec.rb'
- 'ee/spec/models/project_spec.rb'
- 'ee/spec/presenters/group_member_presenter_spec.rb'
- 'ee/spec/requests/api/geo_spec.rb'
- - 'ee/spec/requests/api/graphql/ci/runner_spec.rb'
- 'ee/spec/requests/api/internal/base_spec.rb'
- 'ee/spec/requests/groups/analytics/devops_adoption_controller_spec.rb'
- 'ee/spec/requests/omniauth_kerberos_spnego_spec.rb'
@@ -74,26 +79,32 @@ RSpec/ExpectInHook:
- 'ee/spec/services/ci/minutes/batch_reset_service_spec.rb'
- 'ee/spec/services/ci/runners/assign_runner_service_spec.rb'
- 'ee/spec/services/ci/runners/register_runner_service_spec.rb'
+ - 'ee/spec/services/ci/runners/reset_registration_token_service_spec.rb'
- 'ee/spec/services/ci/runners/unassign_runner_service_spec.rb'
- 'ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb'
- 'ee/spec/services/ee/ci/job_artifacts/destroy_batch_service_spec.rb'
- 'ee/spec/services/ee/issues/update_service_spec.rb'
- - 'ee/spec/services/ee/post_receive_service_spec.rb'
- 'ee/spec/services/ee/protected_branches/destroy_service_spec.rb'
- 'ee/spec/services/geo/blob_download_service_spec.rb'
- 'ee/spec/services/geo/project_housekeeping_service_spec.rb'
- 'ee/spec/services/geo/registry_consistency_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/create_hand_raise_lead_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/fetch_subscription_plans_service_spec.rb'
- 'ee/spec/services/gitlab_subscriptions/plan_upgrade_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/reconciliations/calculate_seat_count_data_service_spec.rb'
- 'ee/spec/services/groups/update_repository_storage_service_spec.rb'
- - 'ee/spec/services/members/activate_service_spec.rb'
+ - 'ee/spec/services/members/await_service_spec.rb'
- 'ee/spec/services/merge_requests/approval_service_spec.rb'
+ - 'ee/spec/services/merge_requests/mergeability/check_approved_service_spec.rb'
+ - 'ee/spec/services/merge_requests/mergeability/check_blocked_by_other_mrs_service_spec.rb'
+ - 'ee/spec/services/merge_requests/mergeability/check_denied_policies_service_spec.rb'
- 'ee/spec/services/projects/create_from_template_service_spec.rb'
- 'ee/spec/services/projects/mark_for_deletion_service_spec.rb'
- 'ee/spec/services/projects/update_mirror_service_spec.rb'
- 'ee/spec/services/security/findings/cleanup_service_spec.rb'
- 'ee/spec/services/upcoming_reconciliations/update_service_spec.rb'
- 'ee/spec/support/shared_examples/controllers/registrations/projects_controller_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/lib/gitlab/graphql/issuables_lazy_links_aggregate_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/concerns/elastic/cannot_read_cross_project_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/concerns/verifiable_replicator_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb'
@@ -112,11 +123,13 @@ RSpec/ExpectInHook:
- 'qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb'
- 'qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb'
- 'qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb'
+ - 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/license/cloud_activation_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/12_geo/wiki_http_push_to_secondary_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/1_manage/instance/instance_audit_logs_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/1_manage/project/project_audit_logs_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/1_manage/project/project_templates_spec.rb'
- 'spec/commands/metrics_server/metrics_server_spec.rb'
+ - 'spec/controllers/admin/runners_controller_spec.rb'
- 'spec/controllers/autocomplete_controller_spec.rb'
- 'spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb'
- 'spec/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support_spec.rb'
@@ -153,13 +166,11 @@ RSpec/ExpectInHook:
- 'spec/features/file_uploads/maven_package_spec.rb'
- 'spec/features/groups/container_registry_spec.rb'
- 'spec/features/groups/group_settings_spec.rb'
- - 'spec/features/issues/filtered_search/dropdown_hint_spec.rb'
- 'spec/features/markdown/markdown_spec.rb'
- 'spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb'
- 'spec/features/merge_request/user_sees_versions_spec.rb'
- 'spec/features/oauth_login_spec.rb'
- 'spec/features/profiles/password_spec.rb'
- - 'spec/features/projects/clusters/gcp_spec.rb'
- 'spec/features/projects/container_registry_spec.rb'
- 'spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb'
- 'spec/features/projects/files/user_creates_files_spec.rb'
@@ -172,17 +183,20 @@ RSpec/ExpectInHook:
- 'spec/features/users/login_spec.rb'
- 'spec/graphql/mutations/design_management/move_spec.rb'
- 'spec/helpers/commits_helper_spec.rb'
+ - 'spec/helpers/groups_helper_spec.rb'
- 'spec/helpers/invite_members_helper_spec.rb'
- 'spec/helpers/projects_helper_spec.rb'
- 'spec/helpers/search_helper_spec.rb'
- 'spec/helpers/users_helper_spec.rb'
- - 'spec/initializers/omniauth_spec.rb'
+ - 'spec/initializers/net_http_response_patch_spec.rb'
- 'spec/initializers/validate_database_config_spec.rb'
- 'spec/lib/api/entities/merge_request_changes_spec.rb'
- 'spec/lib/api/helpers/variables_helpers_spec.rb'
- 'spec/lib/api/helpers_spec.rb'
- 'spec/lib/backup/manager_spec.rb'
- 'spec/lib/banzai/reference_redactor_spec.rb'
+ - 'spec/lib/bulk_imports/common/extractors/json_extractor_spec.rb'
+ - 'spec/lib/bulk_imports/common/extractors/ndjson_extractor_spec.rb'
- 'spec/lib/bulk_imports/ndjson_pipeline_spec.rb'
- 'spec/lib/container_registry/gitlab_api_client_spec.rb'
- 'spec/lib/file_size_validator_spec.rb'
@@ -207,7 +221,6 @@ RSpec/ExpectInHook:
- 'spec/lib/gitlab/ci/pipeline/chain/command_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb'
- 'spec/lib/gitlab/ci/status/build/failed_spec.rb'
- - 'spec/lib/gitlab/ci/trace/archive_spec.rb'
- 'spec/lib/gitlab/ci/trace/remote_checksum_spec.rb'
- 'spec/lib/gitlab/ci/yaml_processor_spec.rb'
- 'spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb'
@@ -216,14 +229,18 @@ RSpec/ExpectInHook:
- 'spec/lib/gitlab/contributions_calendar_spec.rb'
- 'spec/lib/gitlab/current_settings_spec.rb'
- 'spec/lib/gitlab/daemon_spec.rb'
+ - 'spec/lib/gitlab/database/background_migration/batched_migration_runner_spec.rb'
- 'spec/lib/gitlab/database/background_migration/batched_migration_spec.rb'
+ - 'spec/lib/gitlab/database/background_migration/health_status_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/host_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb'
- 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- - 'spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb'
+ - 'spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb'
- 'spec/lib/gitlab/database/migrations/runner_spec.rb'
+ - 'spec/lib/gitlab/database/partitioning/partition_manager_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- 'spec/lib/gitlab/database/partitioning_spec.rb'
+ - 'spec/lib/gitlab/database/postgres_autovacuum_activity_spec.rb'
- 'spec/lib/gitlab/database/query_analyzer_spec.rb'
- 'spec/lib/gitlab/database/with_lock_retries_outside_transaction_spec.rb'
- 'spec/lib/gitlab/database/with_lock_retries_spec.rb'
@@ -251,10 +268,12 @@ RSpec/ExpectInHook:
- 'spec/lib/gitlab/health_checks/gitaly_check_spec.rb'
- 'spec/lib/gitlab/health_checks/probes/collection_spec.rb'
- 'spec/lib/gitlab/health_checks/puma_check_spec.rb'
+ - 'spec/lib/gitlab/health_checks/server_spec.rb'
- 'spec/lib/gitlab/http_spec.rb'
- 'spec/lib/gitlab/import_export/base/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/base/relation_object_saver_spec.rb'
- 'spec/lib/gitlab/import_export/command_line_util_spec.rb'
+ - 'spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb'
- 'spec/lib/gitlab/import_export/group/tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/import_failure_service_spec.rb'
- 'spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb'
@@ -271,12 +290,14 @@ RSpec/ExpectInHook:
- 'spec/lib/gitlab/kubernetes/kube_client_spec.rb'
- 'spec/lib/gitlab/kubernetes/kubeconfig/template_spec.rb'
- 'spec/lib/gitlab/memory/instrumentation_spec.rb'
+ - 'spec/lib/gitlab/memory/jemalloc_spec.rb'
- 'spec/lib/gitlab/metrics/boot_time_tracker_spec.rb'
- 'spec/lib/gitlab/metrics/exporter/metrics_middleware_spec.rb'
- 'spec/lib/gitlab/metrics/samplers/puma_sampler_spec.rb'
- 'spec/lib/gitlab/middleware/memory_report_spec.rb'
- 'spec/lib/gitlab/middleware/multipart_spec.rb'
- 'spec/lib/gitlab/omniauth_initializer_spec.rb'
+ - 'spec/lib/gitlab/pages/deployment_update_spec.rb'
- 'spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb'
- 'spec/lib/gitlab/patch/database_config_spec.rb'
- 'spec/lib/gitlab/project_search_results_spec.rb'
@@ -338,6 +359,7 @@ RSpec/ExpectInHook:
- 'spec/models/ssh_host_key_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/policies/ci/bridge_policy_spec.rb'
+ - 'spec/policies/project_policy_spec.rb'
- 'spec/presenters/ci/build_presenter_spec.rb'
- 'spec/presenters/ci/pipeline_presenter_spec.rb'
- 'spec/presenters/commit_presenter_spec.rb'
@@ -352,6 +374,7 @@ RSpec/ExpectInHook:
- 'spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb'
- 'spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb'
- 'spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb'
+ - 'spec/requests/api/graphql/terraform/state/delete_spec.rb'
- 'spec/requests/api/graphql/terraform/state/lock_spec.rb'
- 'spec/requests/api/graphql/terraform/state/unlock_spec.rb'
- 'spec/requests/api/group_export_spec.rb'
@@ -375,6 +398,7 @@ RSpec/ExpectInHook:
- 'spec/rubocop/cop/performance/ar_count_each_spec.rb'
- 'spec/rubocop/cop/performance/ar_exists_and_present_blank_spec.rb'
- 'spec/scripts/setup/find_jh_branch_spec.rb'
+ - 'spec/scripts/trigger-build_spec.rb'
- 'spec/serializers/diffs_metadata_entity_spec.rb'
- 'spec/serializers/merge_request_diff_entity_spec.rb'
- 'spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
@@ -406,6 +430,7 @@ RSpec/ExpectInHook:
- 'spec/services/design_management/save_designs_service_spec.rb'
- 'spec/services/discussions/capture_diff_note_position_service_spec.rb'
- 'spec/services/environments/reset_auto_stop_service_spec.rb'
+ - 'spec/services/error_tracking/list_projects_service_spec.rb'
- 'spec/services/git/base_hooks_service_spec.rb'
- 'spec/services/git/branch_push_service_spec.rb'
- 'spec/services/git/wiki_push_service/change_spec.rb'
@@ -434,6 +459,7 @@ RSpec/ExpectInHook:
- 'spec/services/notes/quick_actions_service_spec.rb'
- 'spec/services/notification_recipients/builder/default_spec.rb'
- 'spec/services/notification_recipients/builder/new_note_spec.rb'
+ - 'spec/services/packages/cleanup/execute_policy_service_spec.rb'
- 'spec/services/packages/debian/process_changes_service_spec.rb'
- 'spec/services/packages/generic/create_package_file_service_spec.rb'
- 'spec/services/packages/helm/extract_file_metadata_service_spec.rb'
@@ -465,7 +491,6 @@ RSpec/ExpectInHook:
- 'spec/services/protected_branches/create_service_spec.rb'
- 'spec/services/protected_branches/destroy_service_spec.rb'
- 'spec/services/protected_branches/update_service_spec.rb'
- - 'spec/services/repositories/destroy_service_spec.rb'
- 'spec/services/search_service_spec.rb'
- 'spec/services/serverless/associate_domain_service_spec.rb'
- 'spec/services/snippets/update_repository_storage_service_spec.rb'
@@ -481,6 +506,7 @@ RSpec/ExpectInHook:
- 'spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb'
- 'spec/support/shared_examples/graphql/notes_creation_shared_examples.rb'
- 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
+ - 'spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb'
- 'spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb'
- 'spec/support/shared_examples/lib/wikis_api_examples.rb'
- 'spec/support/shared_examples/metrics/sampler_shared_examples.rb'
@@ -515,6 +541,7 @@ RSpec/ExpectInHook:
- 'spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb'
- 'spec/views/shared/runners/_runner_details.html.haml_spec.rb'
- 'spec/workers/build_finished_worker_spec.rb'
+ - 'spec/workers/bulk_imports/pipeline_worker_spec.rb'
- 'spec/workers/ci/build_finished_worker_spec.rb'
- 'spec/workers/concerns/gitlab/github_import/object_importer_spec.rb'
- 'spec/workers/concerns/limited_capacity/job_tracker_spec.rb'
@@ -525,6 +552,7 @@ RSpec/ExpectInHook:
- 'spec/workers/gitlab/jira_import/stage/finish_import_worker_spec.rb'
- 'spec/workers/gitlab_performance_bar_stats_worker_spec.rb'
- 'spec/workers/group_import_worker_spec.rb'
+ - 'spec/workers/incident_management/close_incident_worker_spec.rb'
- 'spec/workers/integrations/create_external_cross_reference_worker_spec.rb'
- 'spec/workers/packages/helm/extraction_worker_spec.rb'
- 'spec/workers/packages/nuget/extraction_worker_spec.rb'
diff --git a/.rubocop_todo/rspec/return_from_stub.yml b/.rubocop_todo/rspec/return_from_stub.yml
index 21cd26a0a6f..215660f31d3 100644
--- a/.rubocop_todo/rspec/return_from_stub.yml
+++ b/.rubocop_todo/rspec/return_from_stub.yml
@@ -1,9 +1,6 @@
---
# Cop supports --auto-correct.
RSpec/ReturnFromStub:
- # Offense count: 703
- # Temporarily disabled due to too many offenses
- Enabled: false
Exclude:
- 'ee/spec/controllers/admin/geo/nodes_controller_spec.rb'
- 'ee/spec/controllers/groups/billings_controller_spec.rb'
@@ -18,6 +15,7 @@ RSpec/ReturnFromStub:
- 'ee/spec/features/projects/integrations/user_activates_jira_spec.rb'
- 'ee/spec/features/projects/milestones/milestone_spec.rb'
- 'ee/spec/features/projects/new_project_spec.rb'
+ - 'ee/spec/features/projects/pipelines/legacy_pipeline_spec.rb'
- 'ee/spec/features/projects/pipelines/pipeline_spec.rb'
- 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
- 'ee/spec/features/promotion_spec.rb'
@@ -39,9 +37,9 @@ RSpec/ReturnFromStub:
- 'ee/spec/lib/ee/feature_spec.rb'
- 'ee/spec/lib/ee/gitlab/checks/push_rules/branch_check_spec.rb'
- 'ee/spec/lib/ee/gitlab/database_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/git_access_project_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/build_consumption_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/cost_factor_spec.rb'
- - 'ee/spec/lib/gitlab/code_owners_spec.rb'
- 'ee/spec/lib/gitlab/geo/health_check_spec.rb'
- 'ee/spec/lib/gitlab/geo/logger_spec.rb'
- 'ee/spec/lib/gitlab/geo_spec.rb'
@@ -62,6 +60,7 @@ RSpec/ReturnFromStub:
- 'ee/spec/presenters/ci/build_presenter_spec.rb'
- 'ee/spec/presenters/merge_request_presenter_spec.rb'
- 'ee/spec/requests/admin/credentials_controller_spec.rb'
+ - 'ee/spec/requests/groups/protected_environments_controller_spec.rb'
- 'ee/spec/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service_spec.rb'
- 'ee/spec/services/auto_merge/merge_train_service_spec.rb'
- 'ee/spec/services/deployments/auto_rollback_service_spec.rb'
@@ -88,6 +87,7 @@ RSpec/ReturnFromStub:
- 'ee/spec/support/shared_examples/services/geo_event_store_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/merge_merge_requests_shared_examples.rb'
- 'ee/spec/views/admin/application_settings/_elasticsearch_form.html.haml_spec.rb'
+ - 'ee/spec/views/admin/application_settings/_git_abuse_rate_limit.html.haml_spec.rb'
- 'ee/spec/views/admin/groups/_form.html.haml_spec.rb'
- 'ee/spec/views/layouts/application.html.haml_spec.rb'
- 'ee/spec/views/shared/_mirror_update_button.html.haml_spec.rb'
@@ -191,13 +191,15 @@ RSpec/ReturnFromStub:
- 'spec/lib/gitlab/instrumentation/redis_base_spec.rb'
- 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
- 'spec/lib/gitlab/memory/instrumentation_spec.rb'
- - 'spec/lib/gitlab/metrics/rails_slis_spec.rb'
+ - 'spec/lib/gitlab/memory/reports_daemon_spec.rb'
- 'spec/lib/gitlab/metrics/system_spec.rb'
- 'spec/lib/gitlab/middleware/read_only_spec.rb'
- 'spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb'
- 'spec/lib/gitlab/prometheus_client_spec.rb'
- 'spec/lib/gitlab/redis/cache_spec.rb'
+ - 'spec/lib/gitlab/redis/duplicate_jobs_spec.rb'
- 'spec/lib/gitlab/redis/shared_state_spec.rb'
+ - 'spec/lib/gitlab/redis/sidekiq_status_spec.rb'
- 'spec/lib/gitlab/relative_positioning/range_spec.rb'
- 'spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb'
- 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb'
diff --git a/Gemfile b/Gemfile
index 71cd2609b3a..4b70737cc3a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,7 +11,7 @@ gem 'responders', '~> 3.0'
gem 'sprockets', '~> 3.7.0'
-gem 'view_component', '~> 2.50.0'
+gem 'view_component', '~> 2.61'
# Default values for AR models
gem 'default_value_for', '~> 3.4.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 6ccdd090ee9..97a73baf0ab 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -692,7 +692,7 @@ GEM
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.10.0)
+ i18n (1.12.0)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
icalendar (2.4.1)
@@ -1429,7 +1429,7 @@ GEM
activesupport (>= 3.0)
version_gem (1.0.0)
version_sorter (2.2.4)
- view_component (2.50.0)
+ view_component (2.61.0)
activesupport (>= 5.0.0, < 8.0)
method_source (~> 1.0)
vmstat (2.3.0)
@@ -1758,7 +1758,7 @@ DEPENDENCIES
valid_email (~> 0.1)
validates_hostname (~> 1.0.11)
version_sorter (~> 2.2.4)
- view_component (~> 2.50.0)
+ view_component (~> 2.61)
vmstat (~> 2.3.0)
warning (~> 1.3.0)
webauthn (~> 2.3)
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue
index bfa99c01c3f..ce221a274c9 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status.vue
@@ -60,7 +60,7 @@ export default {
return this.$options.i18n[`CLEANUP_STATUS_${this.status}`];
},
calculatedTimeTilNextRun() {
- return timeTilRun(this.expirationPolicy?.next_run);
+ return timeTilRun(this.expirationPolicy?.next_run_at);
},
expireIconName() {
return this.failedDelete ? 'expire' : 'clock';
@@ -90,9 +90,9 @@ export default {
{{ statusText }}
</span>
<gl-icon
- v-if="failedDelete"
+ v-if="failedDelete && calculatedTimeTilNextRun"
:id="iconId"
- :size="14"
+ :size="16"
class="gl-text-gray-500"
data-testid="extra-info"
name="information-o"
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
index aecc0bf92ea..80bca536b7c 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue
@@ -95,7 +95,7 @@ export default {
if (this.showFullPath) {
return this.item.path;
}
- const projectPath = this.item?.project?.path ?? '';
+ const projectPath = this.item?.project?.path?.toLowerCase() ?? '';
if (this.item.name) {
return joinPaths(projectPath, this.item.name);
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 1e921b4234e..03dfd0397b0 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -880,8 +880,6 @@ $image-comment-cursor-top-offset: 12;
Security & Compliance Carousel
*/
$security-and-compliance-carousel-image-carousel-width: 1000px;
-$security-and-compliance-carousel-image-discover-button-width: 45%;
-$security-and-compliance-carousel-image-discover-buttons-max-width: 280px;
$security-and-compliance-carousel-image-discover-footer-max-width: 500px;
$security-and-compliance-carousel-image-discover-text-carousel-max-width: 650px;
$security-and-compliance-carousel-image-discover-text-carousel-caption-height: 100%;
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index 4ed38f578ee..f9acd398374 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -40,6 +40,10 @@ class DeployKey < Key
super || User.ghost
end
+ def audit_details
+ title
+ end
+
def has_access_to?(project)
deploy_keys_project_for(project).present?
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index d7e4b53b5de..0a3a0ca00b5 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -280,6 +280,18 @@ module SystemNoteService
::SystemNotes::IssuablesService.new(noteable: mentioned).cross_reference_disallowed?(mentioned_in)
end
+ def relate_work_item(noteable, work_item, user)
+ ::SystemNotes::IssuablesService
+ .new(noteable: noteable, project: noteable.project, author: user)
+ .hierarchy_changed(work_item, 'relate')
+ end
+
+ def unrelate_work_item(noteable, work_item, user)
+ ::SystemNotes::IssuablesService
+ .new(noteable: noteable, project: noteable.project, author: user)
+ .hierarchy_changed(work_item, 'unrelate')
+ end
+
def zoom_link_added(issue, project, author)
::SystemNotes::ZoomService.new(noteable: issue, project: project, author: author).zoom_link_added
end
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index f9e5c3725d8..8da316987b1 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -178,6 +178,24 @@ module SystemNotes
create_note(NoteSummary.new(noteable, project, author, body, action: 'title'))
end
+ # Called when the hierarchy of a work item is changed
+ #
+ # noteable - Noteable object that responds to `work_item_parent` and `work_item_children`
+ # project - Project owning noteable
+ # author - User performing the change
+ #
+ # Example Note text:
+ #
+ # "added #1 as child Task"
+ #
+ # Returns the created Note object
+ def hierarchy_changed(work_item, action)
+ params = hierarchy_note_params(action, noteable, work_item)
+
+ create_note(NoteSummary.new(noteable, project, author, params[:parent_note_body], action: params[:parent_action]))
+ create_note(NoteSummary.new(work_item, project, author, params[:child_note_body], action: params[:child_action]))
+ end
+
# Called when the description of a Noteable is changed
#
# noteable - Noteable object that responds to `description`
@@ -506,6 +524,29 @@ module SystemNotes
def track_cross_reference_action
issue_activity_counter.track_issue_cross_referenced_action(author: author) if noteable.is_a?(Issue)
end
+
+ def hierarchy_note_params(action, parent, child)
+ return {} unless child && parent
+
+ child_type = child.issue_type.humanize(capitalize: false)
+ parent_type = parent.issue_type.humanize(capitalize: false)
+
+ if action == 'relate'
+ {
+ parent_note_body: "added #{child.to_reference} as child #{child_type}",
+ child_note_body: "added #{parent.to_reference} as parent #{parent_type}",
+ parent_action: 'relate_to_child',
+ child_action: 'relate_to_parent'
+ }
+ else
+ {
+ parent_note_body: "removed child #{child_type} #{child.to_reference}",
+ child_note_body: "removed parent #{parent_type} #{parent.to_reference}",
+ parent_action: 'unrelate_from_child',
+ child_action: 'unrelate_from_parent'
+ }
+ end
+ end
end
end
diff --git a/app/services/work_items/parent_links/create_service.rb b/app/services/work_items/parent_links/create_service.rb
index 9940776e367..e7906f1fcdd 100644
--- a/app/services/work_items/parent_links/create_service.rb
+++ b/app/services/work_items/parent_links/create_service.rb
@@ -41,10 +41,8 @@ module WorkItems
params[:issuable_references]
end
- # TODO: Create system notes when work item's parent or children are updated
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/362213
def create_notes(work_item)
- # no-op
+ SystemNoteService.relate_work_item(issuable, work_item, current_user)
end
def target_issuable_type
diff --git a/app/services/work_items/parent_links/destroy_service.rb b/app/services/work_items/parent_links/destroy_service.rb
index 55870d44db9..19770b3e4b5 100644
--- a/app/services/work_items/parent_links/destroy_service.rb
+++ b/app/services/work_items/parent_links/destroy_service.rb
@@ -14,10 +14,8 @@ module WorkItems
private
- # TODO: Create system notes when work item's parent or children are removed
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/362213
def create_notes
- # no-op
+ SystemNoteService.unrelate_work_item(parent, child, current_user)
end
def not_found_message
diff --git a/config/feature_flags/ops/report_jemalloc_stats.yml b/config/feature_flags/ops/report_jemalloc_stats.yml
new file mode 100644
index 00000000000..2bbf63d2d78
--- /dev/null
+++ b/config/feature_flags/ops/report_jemalloc_stats.yml
@@ -0,0 +1,8 @@
+---
+name: report_jemalloc_stats
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91283
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367845
+milestone: '15.2'
+type: ops
+group: group::memory
+default_enabled: false
diff --git a/config/initializers/diagnostic_reports.rb b/config/initializers/diagnostic_reports.rb
new file mode 100644
index 00000000000..b9932822a0b
--- /dev/null
+++ b/config/initializers/diagnostic_reports.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+return unless Gitlab::Utils.to_boolean(ENV['GITLAB_DIAGNOSTIC_REPORTS_ENABLED'])
+
+# Any actions beyond this check should only execute outside of tests,
+# when running in application context (i.e. not in the Rails console or rspec)
+return unless Gitlab::Runtime.application?
+
+Gitlab::Cluster::LifecycleEvents.on_worker_start do
+ Gitlab::Memory::ReportsDaemon.instance.start
+end
diff --git a/doc/administration/geo/replication/docker_registry.md b/doc/administration/geo/replication/docker_registry.md
index 855e33d9a51..5e1614b5554 100644
--- a/doc/administration/geo/replication/docker_registry.md
+++ b/doc/administration/geo/replication/docker_registry.md
@@ -5,40 +5,62 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
-# Docker Registry for a secondary site **(PREMIUM SELF)**
+# Container Registry for a secondary site **(PREMIUM SELF)**
-You can set up a [Docker Registry](https://docs.docker.com/registry/) on your
+You can set up a Container Registry on your
**secondary** Geo site that mirrors the one on the **primary** Geo site.
+## Registry support
+
+Geo supports the following type of container registries:
+
+- [Docker](https://docs.docker.com/registry/)
+- [OCI](https://github.com/opencontainers/distribution-spec/blob/main/spec.md)
+
## Storage support
-Docker Registry currently supports a few types of storage. If you choose a
-distributed storage (`azure`, `gcs`, `s3`, `swift`, or `oss`) for your Docker
+### Docker
+
+[Docker Registry](https://docs.docker.com/registry/) currently supports a few types of storage. If you choose a
+distributed storage (`azure`, `gcs`, `s3`, `swift`, or `oss`) for your Container
Registry on the **primary** site, you can use the same storage for a **secondary**
-Docker Registry as well. For more information, read the
+Container Registry as well. For more information, read the
[Load balancing considerations](https://docs.docker.com/registry/deploying/#load-balancing-considerations)
when deploying the Registry, and how to set up the storage driver for the GitLab
integrated [Container Registry](../../packages/container_registry.md#use-object-storage).
-## Replicating Docker Registry
+### Registries that support OCI artifacts
+
+The following registries support OCI artifacts:
+
+- CNCF Distribution - local/offline verification
+- Azure Container Registry (ACR)
+- Amazon Elastic Container Registry (ECR)
+- Google Artifact Registry (GAR)
+- GitHub Packages container registry (GHCR)
+- Bundle Bar
+
+For more information, see the [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).
+
+## Configure Container Registry replication
You can enable a storage-agnostic replication so it
can be used for cloud or local storage. Whenever a new image is pushed to the
**primary** site, each **secondary** site pulls it to its own container
repository.
-To configure Docker Registry replication:
+To configure Container Registry replication:
1. Configure the [**primary** site](#configure-primary-site).
1. Configure the [**secondary** site](#configure-secondary-site).
-1. Verify Docker Registry [replication](#verify-replication).
+1. Verify Container Registry [replication](#verify-replication).
### Configure **primary** site
Make sure that you have Container Registry set up and working on
the **primary** site before following the next steps.
-We need to make Docker Registry send notification events to the
+We need to make Container Registry send notification events to the
**primary** site.
1. SSH into your GitLab **primary** server and login as root:
@@ -92,7 +114,7 @@ Make sure you have Container Registry set up and working on
the **secondary** site before following the next steps.
The following steps should be done on each **secondary** site you're
-expecting to see the Docker images replicated.
+expecting to see the container images replicated.
Because we need to allow the **secondary** site to communicate securely with
the **primary** site Container Registry, we need to have a single key
diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md
index f699fa6d0fb..f7578ed4554 100644
--- a/doc/user/analytics/index.md
+++ b/doc/user/analytics/index.md
@@ -124,14 +124,14 @@ To retrieve metrics for change failure rate, use the [GraphQL](../../api/graphql
### Supported DORA metrics in GitLab
-| Metric | Level | API | UI chart | Comments |
-|---------------------------|-------------------------|-------------------------------------|---------------------------------------|-------------------------------|
-| `deployment_frequency` | Project | [GitLab 13.7 and later](../../api/dora/metrics.md) | GitLab 14.8 and later | The previous API endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
-| `deployment_frequency` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.12 and later | |
-| `lead_time_for_changes` | Project | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.11 and later | Unit in seconds. Aggregation method is median. |
-| `lead_time_for_changes` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 14.0 and later | Unit in seconds. Aggregation method is median. |
-| `time_to_restore_service` | Project and group | [GitLab 14.9 and later](../../api/dora/metrics.md) | GitLab 15.1 and later | Unit in days. Aggregation method is median. |
-| `change_failure_rate` | Project and group | [GitLab 14.10 and later](../../api/dora/metrics.md) | GitLab 15.2 and later | Percentage of deployments. | |
+| Metric | Level | API | UI chart | Comments |
+|---------------------------|-------------------|-----------------------------------------------------|------------------------|----------|
+| `deployment_frequency` | Project | [GitLab 13.7 and later](../../api/dora/metrics.md) | GitLab 14.8 and later | The previous API endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
+| `deployment_frequency` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.12 and later | |
+| `lead_time_for_changes` | Project | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.11 and later | Unit in seconds. Aggregation method is median. |
+| `lead_time_for_changes` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 14.0 and later | Unit in seconds. Aggregation method is median. |
+| `time_to_restore_service` | Project and group | [GitLab 14.9 and later](../../api/dora/metrics.md) | GitLab 15.1 and later | Unit in days. Aggregation method is median. |
+| `change_failure_rate` | Project and group | [GitLab 14.10 and later](../../api/dora/metrics.md) | GitLab 15.2 and later | Percentage of deployments. |
## Definitions
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index 858b13b87b8..d2b43ed26c2 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -35,10 +35,22 @@ In GitLab, iterations are similar to milestones, with a few differences:
## View the iterations list
-To view the iterations list, go to **{issues}** **Issues > Iterations**.
+To view the iterations list:
+
+1. On the top bar, select **Menu > Projects** and find your project.
+1. Select **Issues > Iterations**.
+
To view all the iterations in a cadence, ordered by descending date, select that iteration cadence.
From there you can create a new iteration or select an iteration to get a more detailed view.
+NOTE:
+If a project has issue tracking
+[turned off](../../project/settings/index.md#configure-project-visibility-features-and-permissions),
+you can view the iterations list
+by going to its URL. To do so, add: `/-/cadences` to your project or group URL.
+For example `https://gitlab.com/gitlab-org/sample-data-templates/sample-gitlab-project/-/cadences`.
+This is tracked in [issue 339009](https://gitlab.com/gitlab-org/gitlab/-/issues/339009).
+
## Create an iteration
> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/356069) in GitLab 14.10.
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index ba48876d4fd..ef734225fb4 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -44,6 +44,14 @@ To view the milestone list:
In a project, GitLab displays milestones that belong to the project.
In a group, GitLab displays milestones that belong to the group and all projects in the group.
+NOTE:
+If a project has issue tracking
+[turned off](../settings/index.md#configure-project-visibility-features-and-permissions),
+you can get to the milestones page
+by going to its URL. To do so, add: `/-/milestones` to your project or group URL.
+For example `https://gitlab.com/gitlab-org/sample-data-templates/sample-gitlab-project/-/milestones`.
+This is tracked in [issue 339009](https://gitlab.com/gitlab-org/gitlab/-/issues/339009).
+
### View all milestones
You can view all the milestones you have access to in the entire GitLab namespace.
diff --git a/lib/gitlab/database/background_migration/batched_job.rb b/lib/gitlab/database/background_migration/batched_job.rb
index 72aa1cfe00b..81898a59da7 100644
--- a/lib/gitlab/database/background_migration/batched_job.rb
+++ b/lib/gitlab/database/background_migration/batched_job.rb
@@ -112,7 +112,7 @@ module Gitlab
end
def can_split?(exception)
- attempts >= MAX_ATTEMPTS && TIMEOUT_EXCEPTIONS.include?(exception&.class) && batch_size > sub_batch_size
+ attempts >= MAX_ATTEMPTS && TIMEOUT_EXCEPTIONS.include?(exception&.class) && batch_size > sub_batch_size && batch_size > 1
end
def split_and_retry!
@@ -121,7 +121,7 @@ module Gitlab
new_batch_size = batch_size / 2
- raise SplitAndRetryError, 'Job cannot be split further' if new_batch_size < 1
+ break update!(attempts: 0) if new_batch_size < 1
batching_strategy = batched_migration.batch_class.new(connection: self.class.connection)
next_batch_bounds = batching_strategy.next_batch(
diff --git a/lib/gitlab/memory/jemalloc.rb b/lib/gitlab/memory/jemalloc.rb
index 454c54569de..fbe5ae656b9 100644
--- a/lib/gitlab/memory/jemalloc.rb
+++ b/lib/gitlab/memory/jemalloc.rb
@@ -14,6 +14,8 @@ module Gitlab
STATS_DEFAULT_FORMAT = :json
+ FILENAME_PREFIX = 'jemalloc_stats'
+
# Return jemalloc stats as a string.
def stats(format: STATS_DEFAULT_FORMAT)
verify_format!(format)
@@ -23,13 +25,17 @@ module Gitlab
end
end
- # Write jemalloc stats to the given directory.
- def dump_stats(path:, format: STATS_DEFAULT_FORMAT)
+ # Write jemalloc stats to the given directory
+ # @param [String] path Directory path the dump will be put into
+ # @param [String] format `json` or `txt`
+ # @param [String] filename_label Optional custom string that will be injected into the file name, e.g. `worker_0`
+ # @return [void]
+ def dump_stats(path:, format: STATS_DEFAULT_FORMAT, filename_label: nil)
verify_format!(format)
with_malloc_stats_print do |stats_print|
format_settings = STATS_FORMATS[format]
- File.open(File.join(path, file_name(format_settings[:extension])), 'wb') do |io|
+ File.open(File.join(path, file_name(format_settings[:extension], filename_label)), 'wb') do |io|
write_stats(stats_print, io, format_settings)
end
end
@@ -80,8 +86,8 @@ module Gitlab
stats_print.call(callback, nil, format[:options])
end
- def file_name(extension)
- "jemalloc_stats.#{$$}.#{Time.current.to_i}.#{extension}"
+ def file_name(extension, filename_label)
+ [FILENAME_PREFIX, $$, filename_label, Time.current.to_i, extension].reject(&:blank?).join('.')
end
end
end
diff --git a/lib/gitlab/memory/reports/jemalloc_stats.rb b/lib/gitlab/memory/reports/jemalloc_stats.rb
new file mode 100644
index 00000000000..b3848d40770
--- /dev/null
+++ b/lib/gitlab/memory/reports/jemalloc_stats.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Memory
+ module Reports
+ class JemallocStats
+ # On prod, Jemalloc reports sizes were ~2.5 MB:
+ # https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/15993#note_1014767214
+ # We configured 1GB emptyDir per pod:
+ # https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/merge_requests/1949
+ # The pod will be evicted when the size limit is exceeded. We never want this to happen, for availability.
+ #
+ # With the default, we have a headroom (250*2.5MB=625<1000 MB) to fit into configured emptyDir.
+ # It would allow us to keep 3+ days worth of reports for 6 workers running every 2 hours: 3*6*12=216<250
+ #
+ # The cleanup logic will be redundant after we'll implement the uploads, which would perform the cleanup.
+ DEFAULT_MAX_REPORTS_STORED = 250
+
+ def initialize(reports_path:)
+ @reports_path = reports_path
+ end
+
+ def run
+ return unless active?
+
+ Gitlab::Memory::Jemalloc.dump_stats(path: reports_path, filename_label: worker_id)
+ cleanup
+ end
+
+ def active?
+ Feature.enabled?(:report_jemalloc_stats, type: :ops)
+ end
+
+ private
+
+ attr_reader :reports_path
+
+ def cleanup
+ reports_files_modified_order[0...-max_reports_stored].each do |f|
+ File.unlink(f) if File.exist?(f)
+ rescue Errno::ENOENT
+ # Path does not exist: Ignore. We already check `File.exist?`
+ # Rescue to be extra safe, because each worker could perform a cleanup
+ end
+ end
+
+ def reports_files_modified_order
+ pattern = File.join(reports_path, "#{Gitlab::Memory::Jemalloc::FILENAME_PREFIX}*")
+
+ Dir.glob(pattern).sort_by do |f|
+ test('M', f)
+ rescue Errno::ENOENT
+ # Path does not exist: Return any timestamp to proceed with the sort
+ Time.current
+ end
+ end
+
+ def worker_id
+ ::Prometheus::PidProvider.worker_id
+ end
+
+ def max_reports_stored
+ ENV["GITLAB_DIAGNOSTIC_REPORTS_JEMALLOC_MAX_REPORTS_STORED"] || DEFAULT_MAX_REPORTS_STORED
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/memory/reports_daemon.rb b/lib/gitlab/memory/reports_daemon.rb
new file mode 100644
index 00000000000..2b2e0915e72
--- /dev/null
+++ b/lib/gitlab/memory/reports_daemon.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Memory
+ class ReportsDaemon < Daemon
+ DEFAULT_SLEEP_S = 7200 # 2 hours
+ DEFAULT_SLEEP_MAX_DELTA_S = 600 # 0..10 minutes
+ DEFAULT_SLEEP_BETWEEN_REPORTS_S = 120 # 2 minutes
+
+ DEFAULT_REPORTS_PATH = '/tmp'
+
+ def initialize(**options)
+ super
+
+ @alive = true
+
+ @sleep_s =
+ ENV['GITLAB_DIAGNOSTIC_REPORTS_SLEEP_S']&.to_i || DEFAULT_SLEEP_S
+ @sleep_max_delta_s =
+ ENV['GITLAB_DIAGNOSTIC_REPORTS_SLEEP_MAX_DELTA_S']&.to_i || DEFAULT_SLEEP_MAX_DELTA_S
+ @sleep_between_reports_s =
+ ENV['GITLAB_DIAGNOSTIC_REPORTS_SLEEP_BETWEEN_REPORTS_S']&.to_i || DEFAULT_SLEEP_BETWEEN_REPORTS_S
+
+ @reports_path =
+ ENV["GITLAB_DIAGNOSTIC_REPORTS_PATH"] || DEFAULT_REPORTS_PATH
+
+ @reports = [Gitlab::Memory::Reports::JemallocStats.new(reports_path: reports_path)]
+
+ init_prometheus_metrics
+ end
+
+ attr_reader :sleep_s, :sleep_max_delta_s, :sleep_between_reports_s, :reports_path
+
+ def run_thread
+ while alive
+ sleep interval_with_jitter
+
+ reports.select(&:active?).each do |report|
+ tms = Benchmark.measure do
+ report.run
+ end
+
+ log_report(report_label(report), tms)
+ @report_duration_counter.increment({ report: report_label(report) }, tms.real.to_i)
+
+ sleep sleep_between_reports_s
+ end
+ end
+ end
+
+ private
+
+ attr_reader :alive, :reports
+
+ # Returns the sleep interval with a random adjustment.
+ # The random adjustment is put in place to ensure continued availability.
+ def interval_with_jitter
+ sleep_s + rand(sleep_max_delta_s)
+ end
+
+ def log_report(report_label, tms)
+ Gitlab::AppLogger.info(
+ message: 'finished',
+ pid: $$,
+ worker_id: worker_id,
+ report: report_label,
+ duration_s: tms.real.round(2),
+ cpu_s: tms.utime.round(2),
+ sys_cpu_s: tms.stime.round(2)
+ )
+ end
+
+ def worker_id
+ ::Prometheus::PidProvider.worker_id
+ end
+
+ def report_label(report)
+ report.class.to_s.demodulize.underscore
+ end
+
+ def stop_working
+ @alive = false
+ end
+
+ def init_prometheus_metrics
+ default_labels = { pid: worker_id }
+
+ @report_duration_counter = Gitlab::Metrics.counter(
+ :gitlab_diag_report_duration_seconds_total,
+ 'Total time elapsed for running diagnostic report',
+ default_labels
+ )
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e51f434bb55..560ac9599b3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -28237,6 +28237,18 @@ msgstr ""
msgid "Personal projects limit:"
msgstr ""
+msgid "PersonalProject|Learn to move a project to a group"
+msgstr ""
+
+msgid "PersonalProject|Some GitLab features, including the ability to upgrade to a paid plan or start a free trial, are only available for groups and projects inside groups. %{projectName} is a personal project, so none of this is available. We recommend you move your project to a group to unlock GitLab's full potential."
+msgstr ""
+
+msgid "PersonalProject|We have some instructions to help you create a group and move your project into it."
+msgstr ""
+
+msgid "PersonalProject|Your project %{projectName} is not in a group"
+msgstr ""
+
msgid "Phabricator Server Import"
msgstr ""
diff --git a/package.json b/package.json
index 2924ef910d3..a30973ee33d 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.28.0",
- "@gitlab/ui": "42.22.0",
+ "@gitlab/ui": "42.22.1",
"@gitlab/visual-review-tools": "1.7.3",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
diff --git a/spec/components/diffs/overflow_warning_component_spec.rb b/spec/components/diffs/overflow_warning_component_spec.rb
index ee4014ee492..88c5de32de7 100644
--- a/spec/components/diffs/overflow_warning_component_spec.rb
+++ b/spec/components/diffs/overflow_warning_component_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Diffs::OverflowWarningComponent, type: :component do
end
describe "rendered component" do
- subject { rendered_component }
+ subject { rendered_content }
context "on a commit page" do
before do
diff --git a/spec/components/diffs/stats_component_spec.rb b/spec/components/diffs/stats_component_spec.rb
index 2e5a5f2ca26..be55c23d040 100644
--- a/spec/components/diffs/stats_component_spec.rb
+++ b/spec/components/diffs/stats_component_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Diffs::StatsComponent, type: :component do
let_it_be(:diff_files) { [diff_file] }
describe "rendered component" do
- subject { rendered_component }
+ subject { page }
let(:element) { page.find(".js-diff-stats-dropdown") }
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
index a5b2b1d7cf8..61503d0f3bf 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/cleanup_status_spec.js
@@ -90,18 +90,26 @@ describe('cleanup_status', () => {
`(
'when the status is $status is $visible that the extra icon is visible',
({ status, visible }) => {
- mountComponent({ status });
+ mountComponent({ status, expirationPolicy: { next_run_at: '2063-04-08T01:44:03Z' } });
expect(findExtraInfoIcon().exists()).toBe(visible);
},
);
+ it(`when the status is ${UNFINISHED_STATUS} & expirationPolicy does not exist the extra icon is not visible`, () => {
+ mountComponent({
+ status: UNFINISHED_STATUS,
+ });
+
+ expect(findExtraInfoIcon().exists()).toBe(false);
+ });
+
it(`has a popover with a learn more link and a time frame for the next run`, () => {
jest.spyOn(Date, 'now').mockImplementation(() => new Date('2063-04-04T00:42:00Z').getTime());
mountComponent({
status: UNFINISHED_STATUS,
- expirationPolicy: { next_run: '2063-04-08T01:44:03Z' },
+ expirationPolicy: { next_run_at: '2063-04-08T01:44:03Z' },
});
expect(findPopover().exists()).toBe(true);
@@ -113,7 +121,7 @@ describe('cleanup_status', () => {
it('id matches popover target attribute', () => {
mountComponent({
status: UNFINISHED_STATUS,
- next_run_at: '2063-04-08T01:44:03Z',
+ expirationPolicy: { next_run_at: '2063-04-08T01:44:03Z' },
});
const id = findExtraInfoIcon().attributes('id');
diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
index f9739509ef9..b11048cd7a2 100644
--- a/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
+++ b/spec/frontend/packages_and_registries/container_registry/explorer/mock_data.js
@@ -13,7 +13,7 @@ export const imagesListResponse = [
expirationPolicyCleanupStatus: 'UNSCHEDULED',
project: {
id: 'gid://gitlab/Project/22',
- path: 'gitlab-test',
+ path: 'GITLAB-TEST',
},
},
{
diff --git a/spec/initializers/diagnostic_reports_spec.rb b/spec/initializers/diagnostic_reports_spec.rb
new file mode 100644
index 00000000000..70574194916
--- /dev/null
+++ b/spec/initializers/diagnostic_reports_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'diagnostic reports' do
+ subject(:load_initializer) do
+ load Rails.root.join('config/initializers/diagnostic_reports.rb')
+ end
+
+ shared_examples 'does not modify worker startup hooks' do
+ it do
+ expect(Gitlab::Cluster::LifecycleEvents).not_to receive(:on_worker_start)
+ expect(Gitlab::Memory::ReportsDaemon).not_to receive(:instance)
+
+ load_initializer
+ end
+ end
+
+ context 'when GITLAB_DIAGNOSTIC_REPORTS_ENABLED is set to true' do
+ before do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_ENABLED', true)
+ end
+
+ context 'when run in application context' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:application?).and_return(true)
+ end
+
+ it 'modifies worker startup hooks' do
+ report_daemon = instance_double(Gitlab::Memory::ReportsDaemon)
+
+ expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_start).and_call_original
+ expect(Gitlab::Memory::ReportsDaemon).to receive(:instance).and_return(report_daemon)
+ expect(report_daemon).to receive(:start)
+
+ load_initializer
+ end
+ end
+
+ context 'when run in non-application context, such as rails console or tests' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:application?).and_return(false)
+ end
+
+ include_examples 'does not modify worker startup hooks'
+ end
+ end
+
+ context 'when GITLAB_DIAGNOSTIC_REPORTS_ENABLED is not set' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:application?).and_return(true)
+ end
+
+ include_examples 'does not modify worker startup hooks'
+ end
+
+ context 'when GITLAB_DIAGNOSTIC_REPORTS_ENABLED is set to false' do
+ before do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_ENABLED', false)
+ allow(::Gitlab::Runtime).to receive(:application?).and_return(true)
+ end
+
+ include_examples 'does not modify worker startup hooks'
+ end
+end
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
index a7b3670da7c..32746a46308 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -304,6 +304,13 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
it { expect(subject).to be_falsey }
end
+
+ context 'when the batch_size is 1' do
+ let(:job) { create(:batched_background_migration_job, :failed, batch_size: 1) }
+ let(:exception) { ActiveRecord::StatementTimeout.new }
+
+ it { expect(subject).to be_falsey }
+ end
end
describe '#time_efficiency' do
@@ -415,10 +422,18 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
end
context 'when batch size is already 1' do
- let!(:job) { create(:batched_background_migration_job, :failed, batch_size: 1) }
+ let!(:job) { create(:batched_background_migration_job, :failed, batch_size: 1, attempts: 3) }
- it 'raises an exception' do
- expect { job.split_and_retry! }.to raise_error 'Job cannot be split further'
+ it 'keeps the same batch size' do
+ job.split_and_retry!
+
+ expect(job.reload.batch_size).to eq 1
+ end
+
+ it 'resets the number of attempts' do
+ job.split_and_retry!
+
+ expect(job.attempts).to eq 0
end
end
diff --git a/spec/lib/gitlab/memory/jemalloc_spec.rb b/spec/lib/gitlab/memory/jemalloc_spec.rb
index 8847516b52c..cd7218330c2 100644
--- a/spec/lib/gitlab/memory/jemalloc_spec.rb
+++ b/spec/lib/gitlab/memory/jemalloc_spec.rb
@@ -52,12 +52,22 @@ RSpec.describe Gitlab::Memory::Jemalloc do
end
describe '.dump_stats' do
- it 'writes stats text file' do
- described_class.dump_stats(path: outdir, format: format)
+ shared_examples 'writes stats text file' do |filename_label, filename_pattern|
+ it do
+ described_class.dump_stats(path: outdir, format: format, filename_label: filename_label)
+
+ file = Dir.entries(outdir).find { |e| e.match(filename_pattern) }
+ expect(file).not_to be_nil
+ expect(File.read(File.join(outdir, file))).to eq(output)
+ end
+ end
- file = Dir.entries(outdir).find { |e| e.match(/jemalloc_stats\.#{$$}\.\d+\.txt$/) }
- expect(file).not_to be_nil
- expect(File.read(File.join(outdir, file))).to eq(output)
+ context 'when custom filename label is passed' do
+ include_examples 'writes stats text file', 'puma_0', /jemalloc_stats\.#{$$}\.puma_0\.\d+\.txt$/
+ end
+
+ context 'when custom filename label is not passed' do
+ include_examples 'writes stats text file', nil, /jemalloc_stats\.#{$$}\.\d+\.txt$/
end
end
end
diff --git a/spec/lib/gitlab/memory/reports/jemalloc_stats_spec.rb b/spec/lib/gitlab/memory/reports/jemalloc_stats_spec.rb
new file mode 100644
index 00000000000..56eeceea174
--- /dev/null
+++ b/spec/lib/gitlab/memory/reports/jemalloc_stats_spec.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Memory::Reports::JemallocStats do
+ let(:jemalloc_stats) { described_class.new(reports_path: '/empty-dir') }
+
+ describe '.run' do
+ context 'when :report_jemalloc_stats ops FF is enabled' do
+ let(:worker_id) {'puma_1'}
+
+ before do
+ allow(Prometheus::PidProvider).to receive(:worker_id).and_return(worker_id)
+ end
+
+ context 'when GITLAB_DIAGNOSTIC_REPORTS_PATH env var is set' do
+ let(:reports_dir) {'/empty-dir'}
+
+ before do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_PATH', reports_dir)
+ end
+
+ it 'writes reports into custom dir while enabled' do
+ expect(Gitlab::Memory::Jemalloc).to receive(:dump_stats).with(path: reports_dir, filename_label: worker_id)
+
+ jemalloc_stats.run
+ end
+ end
+
+ it 'writes reports into default dir while enabled' do
+ expect(Gitlab::Memory::Jemalloc).to receive(:dump_stats).with(path: '/empty-dir', filename_label: worker_id)
+
+ jemalloc_stats.run
+ end
+
+ describe 'reports cleanup' do
+ let_it_be(:outdir) { Dir.mktmpdir }
+
+ let(:jemalloc_stats) { described_class.new(reports_path: outdir) }
+
+ before do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_JEMALLOC_MAX_REPORTS_STORED', 3)
+ allow(Gitlab::Memory::Jemalloc).to receive(:dump_stats)
+ end
+
+ after do
+ FileUtils.rm_f(outdir)
+ end
+
+ context 'when number of reports exceeds `max_reports_stored`' do
+ let_it_be(:reports) do
+ now = Time.current
+
+ (1..5).map do |i|
+ Tempfile.new("jemalloc_stats.#{i}.worker_#{i}.#{Time.current.to_i}.json", outdir).tap do |f|
+ FileUtils.touch(f, mtime: (now + i.second).to_i)
+ end
+ end
+ end
+
+ after do
+ reports.each do |f|
+ f.close
+ f.unlink
+ rescue Errno::ENOENT
+ # Some of the files are already unlinked by the code we test; Ignore
+ end
+ end
+
+ it 'keeps only `max_reports_stored` total newest files' do
+ expect { jemalloc_stats.run }
+ .to change { Dir.entries(outdir).count { |e| e.match(/jemalloc_stats.*/) } }
+ .from(5).to(3)
+
+ # Keeps only the newest reports
+ expect(reports.last(3).all? {|r| File.exist?(r) }).to be true
+ end
+ end
+
+ context 'when number of reports does not exceed `max_reports_stored`' do
+ let_it_be(:reports) do
+ now = Time.current
+
+ (1..3).map do |i|
+ Tempfile.new("jemalloc_stats.#{i}.worker_#{i}.#{Time.current.to_i}.json", outdir).tap do |f|
+ FileUtils.touch(f, mtime: (now + i.second).to_i)
+ end
+ end
+ end
+
+ after do
+ reports.each do |f|
+ f.close
+ f.unlink
+ end
+ end
+
+ it 'does not remove any reports' do
+ expect { jemalloc_stats.run }
+ .not_to change { Dir.entries(outdir).count { |e| e.match(/jemalloc_stats.*/) } }
+ end
+ end
+ end
+ end
+
+ context 'when :report_jemalloc_stats ops FF is disabled' do
+ before do
+ stub_feature_flags(report_jemalloc_stats: false)
+ end
+
+ it 'does not run the report' do
+ expect(Gitlab::Memory::Jemalloc).not_to receive(:dump_stats)
+
+ jemalloc_stats.run
+ end
+ end
+ end
+
+ describe '.active?' do
+ subject(:active) { jemalloc_stats.active? }
+
+ context 'when :report_jemalloc_stats ops FF is enabled' do
+ it { is_expected.to be true }
+ end
+
+ context 'when :report_jemalloc_stats ops FF is disabled' do
+ before do
+ stub_feature_flags(report_jemalloc_stats: false)
+ end
+
+ it { is_expected.to be false }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/memory/reports_daemon_spec.rb b/spec/lib/gitlab/memory/reports_daemon_spec.rb
new file mode 100644
index 00000000000..feac5e2bfb2
--- /dev/null
+++ b/spec/lib/gitlab/memory/reports_daemon_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Memory::ReportsDaemon do
+ let(:daemon) { described_class.new }
+
+ describe '#run_thread' do
+ let(:report_duration_counter) { instance_double(::Prometheus::Client::Counter) }
+
+ before do
+ allow(Gitlab::Metrics).to receive(:counter).and_return(report_duration_counter)
+ allow(report_duration_counter).to receive(:increment)
+
+ # make sleep no-op
+ allow(daemon).to receive(:sleep) {}
+
+ # let alive return 3 times: true, true, false
+ allow(daemon).to receive(:alive).and_return(true, true, false)
+ end
+
+ it 'runs reports' do
+ expect(daemon.send(:reports)).to all(receive(:run).twice)
+
+ daemon.send(:run_thread)
+ end
+
+ it 'logs report execution' do
+ expect(::Prometheus::PidProvider).to receive(:worker_id).at_least(:once).and_return('worker_1')
+
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ hash_including(
+ :duration_s,
+ :cpu_s,
+ :sys_cpu_s,
+ message: 'finished',
+ pid: Process.pid,
+ worker_id: 'worker_1',
+ report: 'jemalloc_stats'
+ )).twice
+
+ daemon.send(:run_thread)
+ end
+
+ it 'sets real time duration gauge' do
+ expect(report_duration_counter).to receive(:increment).with({ report: 'jemalloc_stats' }, an_instance_of(Integer))
+
+ daemon.send(:run_thread)
+ end
+
+ it 'allows configure and run multiple reports' do
+ # rubocop: disable RSpec/VerifiedDoubles
+ # We test how ReportsDaemon could be extended in the future
+ # We configure it with new reports classes which are not yet defined so we cannot make this an instance_double.
+ active_report_1 = double("Active Report 1", active?: true)
+ active_report_2 = double("Active Report 2", active?: true)
+ inactive_report = double("Inactive Report", active?: false)
+ # rubocop: enable RSpec/VerifiedDoubles
+
+ allow(daemon).to receive(:reports).and_return([active_report_1, inactive_report, active_report_2])
+
+ expect(active_report_1).to receive(:run).twice
+ expect(active_report_2).to receive(:run).twice
+ expect(inactive_report).not_to receive(:run)
+
+ daemon.send(:run_thread)
+ end
+
+ context 'sleep timers logic' do
+ it 'wakes up every (fixed interval + defined delta), sleeps between reports each cycle' do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_SLEEP_MAX_DELTA_S', 1) # rand(1) == 0, so we will have fixed sleep interval
+ daemon = described_class.new
+ allow(daemon).to receive(:alive).and_return(true, true, false)
+
+ expect(daemon).to receive(:sleep).with(described_class::DEFAULT_SLEEP_S).ordered
+ expect(daemon).to receive(:sleep).with(described_class::DEFAULT_SLEEP_BETWEEN_REPORTS_S).ordered
+ expect(daemon).to receive(:sleep).with(described_class::DEFAULT_SLEEP_S).ordered
+ expect(daemon).to receive(:sleep).with(described_class::DEFAULT_SLEEP_BETWEEN_REPORTS_S).ordered
+
+ daemon.send(:run_thread)
+ end
+ end
+ end
+
+ describe '#stop_working' do
+ it 'changes :alive to false' do
+ expect { daemon.send(:stop_working) }.to change { daemon.send(:alive) }.from(true).to(false)
+ end
+ end
+
+ context 'timer intervals settings' do
+ context 'when no settings are set in the environment' do
+ it 'uses defaults' do
+ daemon = described_class.new
+
+ expect(daemon.sleep_s).to eq(described_class::DEFAULT_SLEEP_S)
+ expect(daemon.sleep_max_delta_s).to eq(described_class::DEFAULT_SLEEP_MAX_DELTA_S)
+ expect(daemon.sleep_between_reports_s).to eq(described_class::DEFAULT_SLEEP_BETWEEN_REPORTS_S)
+ expect(daemon.reports_path).to eq(described_class::DEFAULT_REPORTS_PATH)
+ end
+ end
+
+ context 'when settings are passed through the environment' do
+ before do
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_SLEEP_S', 100)
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_SLEEP_MAX_DELTA_S', 50)
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_SLEEP_BETWEEN_REPORTS_S', 2)
+ stub_env('GITLAB_DIAGNOSTIC_REPORTS_PATH', '/empty-dir')
+ end
+
+ it 'uses provided values' do
+ daemon = described_class.new
+
+ expect(daemon.sleep_s).to eq(100)
+ expect(daemon.sleep_max_delta_s).to eq(50)
+ expect(daemon.sleep_between_reports_s).to eq(2)
+ expect(daemon.reports_path).to eq('/empty-dir')
+ end
+ end
+ end
+end
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index c22bad0e062..8c3b02427ae 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -146,4 +146,10 @@ RSpec.describe DeployKey, :mailer do
end
end
end
+
+ describe '#audit_details' do
+ it "equals to the key's title" do
+ expect(subject.audit_details).to eq(subject.title)
+ end
+ end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 741d136b9a0..6f15a53da17 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -742,4 +742,38 @@ RSpec.describe SystemNoteService do
described_class.delete_timeline_event(noteable, author)
end
end
+
+ describe '.relate_work_item' do
+ let(:work_item) { double('work_item', issue_type: :task) }
+ let(:noteable) { double }
+
+ before do
+ allow(noteable).to receive(:project).and_return(double)
+ end
+
+ it 'calls IssuableService' do
+ expect_next_instance_of(::SystemNotes::IssuablesService) do |service|
+ expect(service).to receive(:hierarchy_changed).with(work_item, 'relate')
+ end
+
+ described_class.relate_work_item(noteable, work_item, double)
+ end
+ end
+
+ describe '.unrelate_wotk_item' do
+ let(:work_item) { double('work_item', issue_type: :task) }
+ let(:noteable) { double }
+
+ before do
+ allow(noteable).to receive(:project).and_return(double)
+ end
+
+ it 'calls IssuableService' do
+ expect_next_instance_of(::SystemNotes::IssuablesService) do |service|
+ expect(service).to receive(:hierarchy_changed).with(work_item, 'unrelate')
+ end
+
+ described_class.unrelate_work_item(noteable, work_item, double)
+ end
+ end
end
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index 5bc7ea82976..41e4ab1c040 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -886,4 +886,43 @@ RSpec.describe ::SystemNotes::IssuablesService do
it { expect(subject.note).to eq "changed issue type to incident" }
end
+
+ describe '#hierarchy_changed' do
+ let_it_be_with_reload(:work_item) { create(:work_item, project: project) }
+ let_it_be_with_reload(:task) { create(:work_item, :task, project: project) }
+
+ let(:service) { described_class.new(noteable: work_item, project: project, author: author) }
+
+ subject { service.hierarchy_changed(task, hierarchy_change_action) }
+
+ context 'when task is added as a child' do
+ let(:hierarchy_change_action) { 'relate' }
+
+ it_behaves_like 'a system note' do
+ let(:expected_noteable) { task }
+ let(:action) { 'relate_to_parent' }
+ end
+
+ it 'sets the correct note text' do
+ expect { subject }.to change { Note.system.count }.by(2)
+ expect(work_item.notes.last.note).to eq("added ##{task.iid} as child task")
+ expect(task.notes.last.note).to eq("added ##{work_item.iid} as parent issue")
+ end
+ end
+
+ context 'when child task is removed' do
+ let(:hierarchy_change_action) { 'unrelate' }
+
+ it_behaves_like 'a system note' do
+ let(:expected_noteable) { task }
+ let(:action) { 'unrelate_from_parent' }
+ end
+
+ it 'sets the correct note text' do
+ expect { subject }.to change { Note.system.count }.by(2)
+ expect(work_item.notes.last.note).to eq("removed child task ##{task.iid}")
+ expect(task.notes.last.note).to eq("removed parent issue ##{work_item.iid}")
+ end
+ end
+ end
end
diff --git a/spec/services/work_items/parent_links/create_service_spec.rb b/spec/services/work_items/parent_links/create_service_spec.rb
index 85b0ee040cd..ccd23977149 100644
--- a/spec/services/work_items/parent_links/create_service_spec.rb
+++ b/spec/services/work_items/parent_links/create_service_spec.rb
@@ -84,13 +84,26 @@ RSpec.describe WorkItems::ParentLinks::CreateService do
expect(subject[:created_references].map(&:work_item_id)).to match_array([task1.id, task2.id])
end
+ it 'creates notes', :aggregate_failures do
+ subject
+
+ work_item_notes = work_item.notes.last(2)
+ expect(work_item_notes.first.note).to eq("added #{task1.to_reference} as child task")
+ expect(work_item_notes.last.note).to eq("added #{task2.to_reference} as child task")
+ expect(task1.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
+ expect(task2.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
+ end
+
context 'when task is already assigned' do
let(:params) { { issuable_references: [task, task2] } }
- it 'creates links only for non related tasks' do
+ it 'creates links only for non related tasks', :aggregate_failures do
expect { subject }.to change(parent_link_class, :count).by(1)
expect(subject[:created_references].map(&:work_item_id)).to match_array([task2.id])
+ expect(work_item.notes.last.note).to eq("added #{task2.to_reference} as child task")
+ expect(task2.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
+ expect(task.notes).to be_empty
end
end
@@ -109,6 +122,15 @@ RSpec.describe WorkItems::ParentLinks::CreateService do
is_expected.to eq(service_error(error, http_status: 422))
end
+
+ it 'creates notes for valid links' do
+ subject
+
+ expect(work_item.notes.last.note).to eq("added #{task1.to_reference} as child task")
+ expect(task1.notes.last.note).to eq("added #{work_item.to_reference} as parent issue")
+ expect(issue.notes).to be_empty
+ expect(other_project_task.notes).to be_empty
+ end
end
context 'when parent type is invalid' do
diff --git a/spec/services/work_items/parent_links/destroy_service_spec.rb b/spec/services/work_items/parent_links/destroy_service_spec.rb
index 574b70af397..497f7b67266 100644
--- a/spec/services/work_items/parent_links/destroy_service_spec.rb
+++ b/spec/services/work_items/parent_links/destroy_service_spec.rb
@@ -23,8 +23,11 @@ RSpec.describe WorkItems::ParentLinks::DestroyService do
context 'when user has permissions to update work items' do
let(:user) { reporter }
- it 'removes relation' do
+ it 'removes relation and creates notes', :aggregate_failures do
expect { subject }.to change(parent_link_class, :count).by(-1)
+
+ expect(work_item.notes.last.note).to eq("removed child task #{task.to_reference}")
+ expect(task.notes.last.note).to eq("removed parent issue #{work_item.to_reference}")
end
it 'returns success message' do
@@ -35,8 +38,10 @@ RSpec.describe WorkItems::ParentLinks::DestroyService do
context 'when user has insufficient permissions' do
let(:user) { guest }
- it 'does not remove relation' do
+ it 'does not remove relation', :aggregate_failures do
expect { subject }.not_to change(parent_link_class, :count).from(1)
+
+ expect(SystemNoteService).not_to receive(:unrelate_work_item)
end
it 'returns error message' do
diff --git a/spec/support/shared_examples/components/pajamas_shared_examples.rb b/spec/support/shared_examples/components/pajamas_shared_examples.rb
index 5c0ad1a1bc9..955b64152ef 100644
--- a/spec/support/shared_examples/components/pajamas_shared_examples.rb
+++ b/spec/support/shared_examples/components/pajamas_shared_examples.rb
@@ -2,12 +2,12 @@
RSpec.shared_examples 'it renders help text' do
it 'renders help text' do
- expect(rendered_component).to have_selector('[data-testid="pajamas-component-help-text"]', text: help_text)
+ expect(page).to have_css('[data-testid="pajamas-component-help-text"]', text: help_text)
end
end
RSpec.shared_examples 'it does not render help text' do
it 'does not render help text' do
- expect(rendered_component).not_to have_selector('[data-testid="pajamas-component-help-text"]')
+ expect(page).not_to have_css('[data-testid="pajamas-component-help-text"]')
end
end
diff --git a/yarn.lock b/yarn.lock
index 45b79207b6b..adc4ec8c7a3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1053,10 +1053,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.28.0.tgz#a22ad2a4716db18af993d544a628d1d1f128aa7e"
integrity sha512-V1CO91bcYVYuYiYrc6EV02BEzutp06SclzRtC6CRvGoz8mf+qEh7L25a7GxpJyW7hbLo+xajY+IJYhKNmB/qVg==
-"@gitlab/ui@42.22.0":
- version "42.22.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.22.0.tgz#22102109cbe64884fbbc69993f1c517962d78bae"
- integrity sha512-I5n8FeRRgLVyj4FpnXbUUBElTHH1yhCyNarSwcf/qIeR4LeZIOm7Dm5wLAahUlGsStaq0SXlBguImtTRL7Re+g==
+"@gitlab/ui@42.22.1":
+ version "42.22.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-42.22.1.tgz#7ed942f87cd0767c9f8932b69d32c1846bfb388d"
+ integrity sha512-AYdFA1I1fwciwIpfMdBIKjDLUWd4/69Z6asNKLJUf9EGfWS3mUSD0PMMorLxrl+1S5vB07wOo4N9ebSMW3DUMg==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1"