diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:08:38 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 15:08:38 +0000 |
commit | 93b6ee78bf98cbc42712b7c5486ab0e78adb339f (patch) | |
tree | 29efc441f06368d2ec05196fcba070ee37c765b7 | |
parent | 96add3eb957ee4256910087070e27850dd61cfe9 (diff) | |
download | gitlab-ce-93b6ee78bf98cbc42712b7c5486ab0e78adb339f.tar.gz |
Add latest changes from gitlab-org/gitlab@master
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' @@ -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" |