Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2024-01-19 18:10:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2024-01-19 18:10:53 +0300
commit8f3a9dbb94b5a9ae4570a22bbc2a75e7572407c8 (patch)
tree0d7e5d6d5747b57a93df1181bd86a7a127c16934
parent7344cec8c24f1599086498ba19096cf9918ee168 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml2
-rw-r--r--.rubocop_todo/layout/line_length.yml114
-rw-r--r--.rubocop_todo/rspec/context_wording.yml1
-rw-r--r--.rubocop_todo/rspec/expect_change.yml1
-rw-r--r--.rubocop_todo/rspec/feature_category.yml2
-rw-r--r--.rubocop_todo/rspec/named_subject.yml1
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.checksum3
-rw-r--r--Gemfile.lock5
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js25
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/merge_checks.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js6
-rw-r--r--app/controllers/sent_notifications_controller.rb19
-rw-r--r--app/graphql/mutations/work_items/update_task.rb70
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/graphql/types/work_items/updated_task_input_type.rb11
-rw-r--r--app/mailers/emails/service_desk.rb14
-rw-r--r--app/mailers/previews/notify_preview.rb3
-rw-r--r--app/models/sent_notification.rb1
-rw-r--r--app/models/work_items/widgets/base.rb8
-rw-r--r--app/models/work_items/widgets/hierarchy.rb14
-rw-r--r--app/models/work_items/widgets/labels.rb4
-rw-r--r--app/policies/group_policy.rb1
-rw-r--r--app/services/click_house/sync_strategies/base_sync_strategy.rb2
-rw-r--r--app/services/issuable_base_service.rb5
-rw-r--r--app/services/namespace_settings/update_service.rb4
-rw-r--r--app/services/notification_service.rb10
-rw-r--r--app/services/work_items/create_service.rb15
-rw-r--r--app/services/work_items/widgets/labels_service/base_service.rb25
-rw-r--r--app/services/work_items/widgets/labels_service/create_service.rb18
-rw-r--r--app/services/work_items/widgets/labels_service/update_service.rb12
-rw-r--r--app/views/projects/issues/_new_branch.html.haml11
-rw-r--r--app/workers/click_house/concerns/consistency_worker.rb2
-rw-r--r--config/application.rb24
-rw-r--r--config/initializers_before_autoloader/004_zeitwerk.rb1
-rw-r--r--db/docs/ci_freeze_periods.yml2
-rw-r--r--db/docs/ci_resource_groups.yml2
-rw-r--r--db/docs/deploy_keys_projects.yml10
-rw-r--r--db/docs/deployments.yml15
-rw-r--r--db/docs/dora_configurations.yml10
-rw-r--r--db/docs/environments.yml15
-rw-r--r--db/docs/group_deploy_keys_groups.yml10
-rw-r--r--db/docs/group_deploy_tokens.yml10
-rw-r--r--db/docs/project_deploy_tokens.yml10
-rw-r--r--db/migrate/20240104092321_add_issue_email_participant_id_to_sent_notifications.rb9
-rw-r--r--db/migrate/20240104142200_add_index_sent_notifications_on_issue_email_participant_id.rb17
-rw-r--r--db/migrate/20240104142216_add_fk_on_sent_notifications_to_issue_email_participants.rb23
-rw-r--r--db/schema_migrations/202401040923211
-rw-r--r--db/schema_migrations/202401041422001
-rw-r--r--db/schema_migrations/202401041422161
-rw-r--r--db/structure.sql8
-rw-r--r--doc/administration/gitaly/configure_gitaly.md28
-rw-r--r--doc/api/graphql/reference/index.md48
-rw-r--r--doc/api/groups.md6
-rw-r--r--doc/api/usage_data.md32
-rw-r--r--gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb2
-rw-r--r--lib/api/entities/group_detail.rb1
-rw-r--r--lib/api/helpers/groups_helpers.rb1
-rw-r--r--lib/api/usage_data.rb29
-rw-r--r--lib/gitlab/click_house.rb11
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--lib/gitlab/http.rb2
-rw-r--r--lib/gitlab/http_connection_adapter.rb79
-rw-r--r--lib/gitlab/import_export/remote_stream_upload.rb10
-rw-r--r--lib/gitlab/metrics/global_search_slis.rb5
-rw-r--r--lib/gitlab/sidekiq_middleware/pause_control/strategies/click_house_migration.rb2
-rw-r--r--lib/tasks/gitlab/assets.rake2
-rwxr-xr-xscripts/frontend/clean_css_assets.mjs72
-rwxr-xr-xscripts/frontend/compare_css_compilers.sh35
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb32
-rw-r--r--spec/frontend/content_editor/extensions/attachment_spec.js398
-rw-r--r--spec/graphql/mutations/work_items/update_task_spec.rb36
-rw-r--r--spec/lib/api/entities/group_detail_spec.rb46
-rw-r--r--spec/lib/gitlab/click_house_spec.rb17
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb14
-rw-r--r--spec/lib/gitlab/http_connection_adapter_spec.rb161
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/remote_stream_upload_spec.rb26
-rw-r--r--spec/lib/gitlab/metrics/global_search_slis_spec.rb48
-rw-r--r--spec/mailers/emails/service_desk_spec.rb24
-rw-r--r--spec/mailers/notify_spec.rb7
-rw-r--r--spec/models/sent_notification_spec.rb22
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_task_spec.rb85
-rw-r--r--spec/requests/api/groups_spec.rb30
-rw-r--r--spec/requests/api/usage_data_spec.rb58
-rw-r--r--spec/services/click_house/sync_strategies/base_sync_strategy_spec.rb4
-rw-r--r--spec/services/click_house/sync_strategies/event_sync_strategy_spec.rb6
-rw-r--r--spec/services/namespace_settings/update_service_spec.rb1
-rw-r--r--spec/services/notification_service_spec.rb85
-rw-r--r--spec/services/work_items/widgets/labels_service/create_service_spec.rb56
-rw-r--r--spec/support/rspec_order_todo.yml3
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb1
-rw-r--r--spec/workers/click_house/event_authors_consistency_cron_worker_spec.rb4
-rw-r--r--workhorse/internal/helper/command/command.go6
-rw-r--r--workhorse/internal/helper/command/command_test.go97
97 files changed, 1418 insertions, 814 deletions
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index 4d3c8eb4a90..4cc5f4ffef0 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -1136,7 +1136,6 @@ Gitlab/NamespacedClass:
- 'lib/gitlab/highlight.rb'
- 'lib/gitlab/hotlinking_detector.rb'
- 'lib/gitlab/http.rb'
- - 'lib/gitlab/http_connection_adapter.rb'
- 'lib/gitlab/http_io.rb'
- 'lib/gitlab/import_formatter.rb'
- 'lib/gitlab/inactive_projects_deletion_warning_tracker.rb'
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index cf490823f76..5f90ff11fd3 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -147,7 +147,6 @@ Layout/ArgumentAlignment:
- 'app/graphql/mutations/work_items/create_from_task.rb'
- 'app/graphql/mutations/work_items/delete.rb'
- 'app/graphql/mutations/work_items/update.rb'
- - 'app/graphql/mutations/work_items/update_task.rb'
- 'app/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver.rb'
- 'app/graphql/resolvers/alert_management/alert_resolver.rb'
- 'app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb'
@@ -1214,7 +1213,6 @@ Layout/ArgumentAlignment:
- 'lib/gitlab/graphql/expose_permissions.rb'
- 'lib/gitlab/graphql/mount_mutation.rb'
- 'lib/gitlab/graphql/negatable_arguments.rb'
- - 'lib/gitlab/http_connection_adapter.rb'
- 'lib/gitlab/import_export/base/relation_object_saver.rb'
- 'lib/gitlab/import_export/importer.rb'
- 'lib/gitlab/import_export/members_mapper.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index 4f51b3f614a..378c8adc69c 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -132,7 +132,6 @@ Layout/LineLength:
- 'app/graphql/mutations/merge_requests/set_labels.rb'
- 'app/graphql/mutations/merge_requests/set_locked.rb'
- 'app/graphql/mutations/merge_requests/set_milestone.rb'
- - 'app/graphql/mutations/metrics/dashboard/annotations/create.rb'
- 'app/graphql/mutations/namespace/package_settings/update.rb'
- 'app/graphql/mutations/notes/create/note.rb'
- 'app/graphql/mutations/packages/destroy.rb'
@@ -224,7 +223,6 @@ Layout/LineLength:
- 'app/helpers/import_helper.rb'
- 'app/helpers/in_product_marketing_helper.rb'
- 'app/helpers/issuables_helper.rb'
- - 'app/helpers/jira_connect_helper.rb'
- 'app/helpers/labels_helper.rb'
- 'app/helpers/merge_requests_helper.rb'
- 'app/helpers/mirror_helper.rb'
@@ -335,7 +333,6 @@ Layout/LineLength:
- 'app/models/integrations/base_chat_notification.rb'
- 'app/models/integrations/base_issue_tracker.rb'
- 'app/models/integrations/bugzilla.rb'
- - 'app/models/integrations/chat_message/deployment_message.rb'
- 'app/models/integrations/chat_message/merge_message.rb'
- 'app/models/integrations/chat_message/note_message.rb'
- 'app/models/integrations/chat_message/pipeline_message.rb'
@@ -348,7 +345,6 @@ Layout/LineLength:
- 'app/models/integrations/emails_on_push.rb'
- 'app/models/integrations/ewm.rb'
- 'app/models/integrations/external_wiki.rb'
- - 'app/models/integrations/hangouts_chat.rb'
- 'app/models/integrations/harbor.rb'
- 'app/models/integrations/jenkins.rb'
- 'app/models/integrations/mattermost.rb'
@@ -372,7 +368,6 @@ Layout/LineLength:
- 'app/models/lfs_object.rb'
- 'app/models/lfs_objects_project.rb'
- 'app/models/list.rb'
- - 'app/models/loose_foreign_keys/modification_tracker.rb'
- 'app/models/member.rb'
- 'app/models/merge_request.rb'
- 'app/models/merge_request_assignee.rb'
@@ -403,7 +398,6 @@ Layout/LineLength:
- 'app/models/project_statistics.rb'
- 'app/models/projects/topic.rb'
- 'app/models/prometheus_metric.rb'
- - 'app/models/protected_branch/push_access_level.rb'
- 'app/models/release.rb'
- 'app/models/releases/link.rb'
- 'app/models/remote_mirror.rb'
@@ -448,7 +442,6 @@ Layout/LineLength:
- 'app/serializers/merge_request_sidebar_extras_entity.rb'
- 'app/serializers/merge_request_widget_entity.rb'
- 'app/serializers/note_entity.rb'
- - 'app/serializers/project_note_entity.rb'
- 'app/services/application_settings/update_service.rb'
- 'app/services/auth/container_registry_authentication_service.rb'
- 'app/services/auto_merge/merge_when_pipeline_succeeds_service.rb'
@@ -460,7 +453,6 @@ Layout/LineLength:
- 'app/services/bulk_imports/uploads_export_service.rb'
- 'app/services/ci/create_pipeline_service.rb'
- 'app/services/ci/drop_pipeline_service.rb'
- - 'app/services/ci/generate_coverage_reports_service.rb'
- 'app/services/ci/job_artifacts/expire_project_build_artifacts_service.rb'
- 'app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb'
- 'app/services/ci/pipelines/add_job_service.rb'
@@ -504,11 +496,9 @@ Layout/LineLength:
- 'app/services/groups/update_service.rb'
- 'app/services/import/bitbucket_server_service.rb'
- 'app/services/import/github_service.rb'
- - 'app/services/import/validate_remote_git_endpoint_service.rb'
- 'app/services/issuable/process_assignees.rb'
- 'app/services/issuable_base_service.rb'
- 'app/services/issuable_links/create_service.rb'
- - 'app/services/issues/base_service.rb'
- 'app/services/issues/clone_service.rb'
- 'app/services/issues/close_service.rb'
- 'app/services/issues/duplicate_service.rb'
@@ -534,7 +524,6 @@ Layout/LineLength:
- 'app/services/merge_requests/base_service.rb'
- 'app/services/merge_requests/build_service.rb'
- 'app/services/merge_requests/create_from_issue_service.rb'
- - 'app/services/merge_requests/merge_base_service.rb'
- 'app/services/merge_requests/merge_service.rb'
- 'app/services/merge_requests/mergeability_check_service.rb'
- 'app/services/merge_requests/push_options_handler_service.rb'
@@ -581,7 +570,6 @@ Layout/LineLength:
- 'app/services/projects/overwrite_project_service.rb'
- 'app/services/projects/transfer_service.rb'
- 'app/services/projects/unlink_fork_service.rb'
- - 'app/services/projects/update_pages_service.rb'
- 'app/services/projects/update_service.rb'
- 'app/services/protected_branches/update_service.rb'
- 'app/services/quick_actions/target_service.rb'
@@ -675,7 +663,6 @@ Layout/LineLength:
- 'config/routes/import.rb'
- 'config/routes/project.rb'
- 'config/routes/repository.rb'
- - 'config/routes/uploads.rb'
- 'config/routes/user.rb'
- 'config/settings.rb'
- 'danger/ci_config/Dangerfile'
@@ -685,7 +672,6 @@ Layout/LineLength:
- 'danger/roulette/Dangerfile'
- 'danger/vue_shared_documentation/Dangerfile'
- 'ee/app/controllers/admin/elasticsearch_controller.rb'
- - 'ee/app/controllers/admin/geo/application_controller.rb'
- 'ee/app/controllers/admin/licenses_controller.rb'
- 'ee/app/controllers/concerns/audit_events/date_range.rb'
- 'ee/app/controllers/concerns/credentials_inventory_actions.rb'
@@ -730,7 +716,6 @@ Layout/LineLength:
- 'ee/app/graphql/ee/mutations/ci/runner/update.rb'
- 'ee/app/graphql/mutations/analytics/devops_adoption/enabled_namespaces/bulk_enable.rb'
- 'ee/app/graphql/mutations/audit_events/external_audit_event_destinations/create.rb'
- - 'ee/app/graphql/mutations/audit_events/external_audit_event_destinations/update.rb'
- 'ee/app/graphql/mutations/boards/epic_boards/epic_move_list.rb'
- 'ee/app/graphql/mutations/boards/scoped_issue_board_arguments.rb'
- 'ee/app/graphql/mutations/compliance_management/frameworks/destroy.rb'
@@ -807,7 +792,6 @@ Layout/LineLength:
- 'ee/app/helpers/billing_plans_helper.rb'
- 'ee/app/helpers/ee/application_helper.rb'
- 'ee/app/helpers/ee/button_helper.rb'
- - 'ee/app/helpers/ee/geo_helper.rb'
- 'ee/app/helpers/ee/groups/settings_helper.rb'
- 'ee/app/helpers/ee/groups_helper.rb'
- 'ee/app/helpers/ee/import_helper.rb'
@@ -818,7 +802,6 @@ Layout/LineLength:
- 'ee/app/helpers/ee/merge_requests_helper.rb'
- 'ee/app/helpers/ee/mirror_helper.rb'
- 'ee/app/helpers/ee/notes_helper.rb'
- - 'ee/app/helpers/ee/personal_access_tokens_helper.rb'
- 'ee/app/helpers/ee/profiles_helper.rb'
- 'ee/app/helpers/ee/projects_helper.rb'
- 'ee/app/helpers/ee/search_helper.rb'
@@ -878,7 +861,6 @@ Layout/LineLength:
- 'ee/app/models/ee/packages/package_file.rb'
- 'ee/app/models/ee/pages_deployment.rb'
- 'ee/app/models/ee/project.rb'
- - 'ee/app/models/ee/resource_label_event.rb'
- 'ee/app/models/ee/snippet_repository.rb'
- 'ee/app/models/ee/terraform/state_version.rb'
- 'ee/app/models/ee/upload.rb'
@@ -901,7 +883,6 @@ Layout/LineLength:
- 'ee/app/models/merge_requests/compliance_violation.rb'
- 'ee/app/models/merge_requests/external_status_check.rb'
- 'ee/app/models/productivity_analytics.rb'
- - 'ee/app/models/project_repository_state.rb'
- 'ee/app/models/protected_environment.rb'
- 'ee/app/models/requirements_management/requirement.rb'
- 'ee/app/models/requirements_management/test_report.rb'
@@ -952,7 +933,6 @@ Layout/LineLength:
- 'ee/app/services/app_sec/dast/site_validations/runner_service.rb'
- 'ee/app/services/audit_events/runner_audit_event_service.rb'
- 'ee/app/services/audit_events/runner_custom_audit_event_service.rb'
- - 'ee/app/services/audit_events/user_impersonation_group_audit_event_service.rb'
- 'ee/app/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service.rb'
- 'ee/app/services/boards/epics/create_service.rb'
- 'ee/app/services/boards/epics/move_service.rb'
@@ -1019,7 +999,6 @@ Layout/LineLength:
- 'ee/app/services/incident_management/incidents/upload_metric_service.rb'
- 'ee/app/services/incident_management/oncall_rotations/create_service.rb'
- 'ee/app/services/incident_management/oncall_rotations/edit_service.rb'
- - 'ee/app/services/incident_management/oncall_schedules/update_service.rb'
- 'ee/app/services/incident_management/pending_escalations/process_service.rb'
- 'ee/app/services/iterations/cadences/create_iterations_in_advance_service.rb'
- 'ee/app/services/iterations/cadences/create_service.rb'
@@ -1031,7 +1010,6 @@ Layout/LineLength:
- 'ee/app/services/jira/jql_builder_service.rb'
- 'ee/app/services/jira/requests/issues/list_service.rb'
- 'ee/app/services/merge_requests/create_from_vulnerability_data_service.rb'
- - 'ee/app/services/merge_trains/create_pipeline_service.rb'
- 'ee/app/services/merge_trains/refresh_merge_request_service.rb'
- 'ee/app/services/personal_access_tokens/rotation_verifier_service.rb'
- 'ee/app/services/projects/mark_for_deletion_service.rb'
@@ -1170,7 +1148,6 @@ Layout/LineLength:
- 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
- 'ee/lib/ee/gitlab/checks/push_rules/commit_check.rb'
- 'ee/lib/ee/gitlab/checks/push_rules/file_size_check.rb'
- - 'ee/lib/ee/gitlab/ci/config_ee.rb'
- 'ee/lib/ee/gitlab/ci/pipeline/chain/create_cross_database_associations.rb'
- 'ee/lib/ee/gitlab/ci/pipeline/chain/validate/after_config.rb'
- 'ee/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb'
@@ -1212,7 +1189,6 @@ Layout/LineLength:
- 'ee/lib/gitlab/auth/group_saml/xml_response.rb'
- 'ee/lib/gitlab/authority_analyzer.rb'
- 'ee/lib/gitlab/ci/config/security_orchestration_policies/processor.rb'
- - 'ee/lib/gitlab/ci/reports/dependency_list/report.rb'
- 'ee/lib/gitlab/ci/reports/security/locations/cluster_image_scanning.rb'
- 'ee/lib/gitlab/contribution_analytics/data_collector.rb'
- 'ee/lib/gitlab/elastic/group_search_results.rb'
@@ -1237,7 +1213,6 @@ Layout/LineLength:
- 'ee/lib/gitlab/insights/serializers/chartjs/bar_serializer.rb'
- 'ee/lib/gitlab/insights/serializers/chartjs/multi_series_serializer.rb'
- 'ee/lib/gitlab/insights/validators/params_validator.rb'
- - 'ee/lib/gitlab/ip_restriction/enforcer.rb'
- 'ee/lib/gitlab/manual_quarterly_co_term_banner.rb'
- 'ee/lib/gitlab/sitemaps/generator.rb'
- 'ee/lib/gitlab/status_page/storage/s3_client.rb'
@@ -1287,14 +1262,12 @@ Layout/LineLength:
- 'ee/spec/controllers/projects/pipelines_controller_spec.rb'
- 'ee/spec/controllers/projects/protected_environments_controller_spec.rb'
- 'ee/spec/controllers/projects/push_rules_controller_spec.rb'
- - 'ee/spec/controllers/projects/security/configuration_controller_spec.rb'
- 'ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb'
- 'ee/spec/controllers/projects/subscriptions_controller_spec.rb'
- 'ee/spec/controllers/projects/vulnerability_feedback_controller_spec.rb'
- 'ee/spec/controllers/projects_controller_spec.rb'
- 'ee/spec/controllers/subscriptions_controller_spec.rb'
- 'ee/spec/elastic/migrate/migration_shared_examples.rb'
- - 'ee/spec/factories/ci/builds.rb'
- 'ee/spec/factories/ci/job_artifacts.rb'
- 'ee/spec/factories/ci/pipelines.rb'
- 'ee/spec/factories/ci/reports/license_scanning/report.rb'
@@ -1349,7 +1322,6 @@ Layout/LineLength:
- 'ee/spec/features/groups/security/compliance_dashboards_spec.rb'
- 'ee/spec/features/integrations/jira/jira_issues_list_spec.rb'
- 'ee/spec/features/issues/filtered_search/filter_issues_weight_spec.rb'
- - 'ee/spec/features/issues/form_spec.rb'
- 'ee/spec/features/labels_hierarchy_spec.rb'
- 'ee/spec/features/merge_request/user_approves_spec.rb'
- 'ee/spec/features/merge_request/user_approves_with_password_spec.rb'
@@ -1361,12 +1333,10 @@ Layout/LineLength:
- 'ee/spec/features/merge_request/user_sets_approvers_spec.rb'
- 'ee/spec/features/merge_requests/user_filters_by_approvers_spec.rb'
- 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
- - 'ee/spec/features/merge_trains/user_adds_to_merge_train_when_pipeline_succeeds_spec.rb'
- 'ee/spec/features/pending_group_memberships_spec.rb'
- 'ee/spec/features/projects/audit_events_spec.rb'
- 'ee/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb'
- 'ee/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb'
- - 'ee/spec/features/projects/integrations/user_activates_jira_spec.rb'
- 'ee/spec/features/projects/iterations/iteration_cadences_list_spec.rb'
- 'ee/spec/features/projects/iterations/user_views_iteration_spec.rb'
- 'ee/spec/features/projects/licenses/maintainer_views_policies_spec.rb'
@@ -1375,7 +1345,6 @@ Layout/LineLength:
- 'ee/spec/features/projects/new_project_spec.rb'
- 'ee/spec/features/projects/pipelines/pipeline_spec.rb'
- 'ee/spec/features/projects/quality/test_case_list_spec.rb'
- - 'ee/spec/features/projects/quality/test_case_show_spec.rb'
- 'ee/spec/features/projects/requirements_management/requirements_list_spec.rb'
- 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
- 'ee/spec/features/projects/settings/issues_settings_spec.rb'
@@ -1435,7 +1404,6 @@ Layout/LineLength:
- 'ee/spec/graphql/mutations/boards/epics/create_spec.rb'
- 'ee/spec/graphql/mutations/boards/lists/update_limit_metrics_spec.rb'
- 'ee/spec/graphql/mutations/compliance_management/frameworks/update_spec.rb'
- - 'ee/spec/graphql/mutations/dast/profiles/run_spec.rb'
- 'ee/spec/graphql/mutations/dast_on_demand_scans/create_spec.rb'
- 'ee/spec/graphql/mutations/dast_scanner_profiles/update_spec.rb'
- 'ee/spec/graphql/mutations/dast_site_profiles/create_spec.rb'
@@ -1507,16 +1475,12 @@ Layout/LineLength:
- 'ee/spec/helpers/ee/application_settings_helper_spec.rb'
- 'ee/spec/helpers/ee/branches_helper_spec.rb'
- 'ee/spec/helpers/ee/ci/pipelines_helper_spec.rb'
- - 'ee/spec/helpers/ee/dashboard_helper_spec.rb'
- 'ee/spec/helpers/ee/feature_flags_helper_spec.rb'
- 'ee/spec/helpers/ee/gitlab_routing_helper_spec.rb'
- 'ee/spec/helpers/ee/groups/group_members_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/lock_helper_spec.rb'
- 'ee/spec/helpers/ee/operations_helper_spec.rb'
- - 'ee/spec/helpers/ee/personal_access_tokens_helper_spec.rb'
- 'ee/spec/helpers/ee/projects/pipeline_helper_spec.rb'
- 'ee/spec/helpers/ee/projects/security/api_fuzzing_configuration_helper_spec.rb'
- 'ee/spec/helpers/ee/projects/security/dast_configuration_helper_spec.rb'
@@ -1619,7 +1583,6 @@ Layout/LineLength:
- 'ee/spec/lib/gitlab/ci/config/entry/job_spec.rb'
- 'ee/spec/lib/gitlab/ci/config/security_orchestration_policies/processor_spec.rb'
- 'ee/spec/lib/gitlab/ci/minutes/cost_factor_spec.rb'
- - 'ee/spec/lib/gitlab/ci/minutes/runners_availability_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/license_compliance/license_scanning_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/security/cluster_image_scanning_spec.rb'
- 'ee/spec/lib/gitlab/ci/parsers/security/container_scanning_spec.rb'
@@ -1694,7 +1657,6 @@ Layout/LineLength:
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_associating_group_milestones_to_releases_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric_spec.rb'
- 'ee/spec/lib/gitlab/usage/metrics/instrumentations/license_metric_spec.rb'
- - 'ee/spec/lib/gitlab/usage_data_metrics_spec.rb'
- 'ee/spec/lib/gitlab_subscriptions/upcoming_reconciliation_entity_spec.rb'
- 'ee/spec/lib/incident_management/oncall_shift_generator_spec.rb'
- 'ee/spec/lib/omni_auth/strategies/group_saml_spec.rb'
@@ -1762,16 +1724,19 @@ Layout/LineLength:
- 'ee/spec/models/ee/audit_event_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'ee/spec/models/ee/ci/pipeline_artifact_spec.rb'
+ - 'ee/spec/models/ee/group_member_spec.rb'
- 'ee/spec/models/ee/group_spec.rb'
- 'ee/spec/models/ee/incident_management/project_incident_management_setting_spec.rb'
- 'ee/spec/models/ee/integrations/jira_spec.rb'
- 'ee/spec/models/ee/iterations/cadence_spec.rb'
- 'ee/spec/models/ee/lfs_object_spec.rb'
+ - 'ee/spec/models/ee/member_spec.rb'
- 'ee/spec/models/ee/merge_request_diff_spec.rb'
- 'ee/spec/models/ee/namespace_spec.rb'
- 'ee/spec/models/ee/namespace_statistics_spec.rb'
- 'ee/spec/models/ee/preloaders/group_policy_preloader_spec.rb'
- 'ee/spec/models/ee/project_authorization_spec.rb'
+ - 'ee/spec/models/ee/project_member_spec.rb'
- 'ee/spec/models/ee/project_spec.rb'
- 'ee/spec/models/ee/protected_branch_spec.rb'
- 'ee/spec/models/ee/service_desk_setting_spec.rb'
@@ -1790,7 +1755,6 @@ Layout/LineLength:
- 'ee/spec/models/geo_node_status_spec.rb'
- 'ee/spec/models/gitlab_subscription_spec.rb'
- 'ee/spec/models/gitlab_subscriptions/features_spec.rb'
- - 'ee/spec/models/ee/group_member_spec.rb'
- 'ee/spec/models/historical_data_spec.rb'
- 'ee/spec/models/incident_management/escalation_policy_spec.rb'
- 'ee/spec/models/incident_management/escalation_rule_spec.rb'
@@ -1803,7 +1767,6 @@ Layout/LineLength:
- 'ee/spec/models/issue_spec.rb'
- 'ee/spec/models/iteration_spec.rb'
- 'ee/spec/models/license_spec.rb'
- - 'ee/spec/models/ee/member_spec.rb'
- 'ee/spec/models/merge_request_spec.rb'
- 'ee/spec/models/merge_requests/compliance_violation_spec.rb'
- 'ee/spec/models/merge_requests/external_status_check_spec.rb'
@@ -1812,7 +1775,6 @@ Layout/LineLength:
- 'ee/spec/models/packages/package_file_spec.rb'
- 'ee/spec/models/project_import_data_spec.rb'
- 'ee/spec/models/project_import_state_spec.rb'
- - 'ee/spec/models/ee/project_member_spec.rb'
- 'ee/spec/models/project_security_setting_spec.rb'
- 'ee/spec/models/protected_environment_spec.rb'
- 'ee/spec/models/protected_environments/approval_rule_spec.rb'
@@ -1840,10 +1802,8 @@ Layout/LineLength:
- 'ee/spec/models/vulnerabilities/statistic_spec.rb'
- 'ee/spec/policies/group_policy_spec.rb'
- 'ee/spec/policies/issuable_policy_spec.rb'
- - 'ee/spec/policies/issue_policy_spec.rb'
- 'ee/spec/policies/merge_request_policy_spec.rb'
- 'ee/spec/policies/project_policy_spec.rb'
- - 'ee/spec/policies/protected_branch_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/export_policy_spec.rb'
- 'ee/spec/policies/vulnerabilities/external_issue_link_policy_spec.rb'
- 'ee/spec/presenters/audit_event_presenter_spec.rb'
@@ -1860,7 +1820,6 @@ Layout/LineLength:
- 'ee/spec/requests/admin/user_permission_exports_controller_spec.rb'
- 'ee/spec/requests/api/analytics/code_review_analytics_spec.rb'
- 'ee/spec/requests/api/audit_events_spec.rb'
- - 'ee/spec/requests/api/branches_spec.rb'
- 'ee/spec/requests/api/ci/jobs_spec.rb'
- 'ee/spec/requests/api/ci/minutes_spec.rb'
- 'ee/spec/requests/api/ci/pipelines_spec.rb'
@@ -1870,7 +1829,6 @@ Layout/LineLength:
- 'ee/spec/requests/api/elasticsearch_indexed_namespaces_spec.rb'
- 'ee/spec/requests/api/epic_issues_spec.rb'
- 'ee/spec/requests/api/epics_spec.rb'
- - 'ee/spec/requests/api/geo_nodes_spec.rb'
- 'ee/spec/requests/api/geo_spec.rb'
- 'ee/spec/requests/api/graphql/analytics/devops_adoption/enabled_namespaces_spec.rb'
- 'ee/spec/requests/api/graphql/boards/board_list_query_spec.rb'
@@ -1878,7 +1836,6 @@ Layout/LineLength:
- 'ee/spec/requests/api/graphql/boards/epic_boards_query_spec.rb'
- 'ee/spec/requests/api/graphql/compliance_management/merge_requests/compliance_violations_spec.rb'
- 'ee/spec/requests/api/graphql/current_user/groups_query_spec.rb'
- - 'ee/spec/requests/api/graphql/epics/epic_resolver_spec.rb'
- 'ee/spec/requests/api/graphql/group/dast_profile_schedule_spec.rb'
- 'ee/spec/requests/api/graphql/group/epic/epic_aggregate_query_spec.rb'
- 'ee/spec/requests/api/graphql/group/epics_spec.rb'
@@ -1978,7 +1935,6 @@ Layout/LineLength:
- 'ee/spec/requests/groups/group_members_controller_spec.rb'
- 'ee/spec/requests/groups/roadmap_controller_spec.rb'
- 'ee/spec/requests/groups/security/credentials_controller_spec.rb'
- - 'ee/spec/requests/groups_controller_spec.rb'
- 'ee/spec/requests/jwt_controller_spec.rb'
- 'ee/spec/requests/lfs_http_spec.rb'
- 'ee/spec/requests/projects/merge_requests_controller_spec.rb'
@@ -2083,10 +2039,8 @@ Layout/LineLength:
- 'ee/spec/services/ee/issues/move_service_spec.rb'
- 'ee/spec/services/ee/issues/update_service_spec.rb'
- 'ee/spec/services/ee/members/destroy_service_spec.rb'
- - 'ee/spec/services/merge_requests/create_from_vulnerability_data_service_spec.rb'
- 'ee/spec/services/ee/merge_requests/post_merge_service_spec.rb'
- 'ee/spec/services/ee/merge_requests/refresh_service_spec.rb'
- - 'ee/spec/services/ee/merge_requests/update_service_spec.rb'
- 'ee/spec/services/ee/notes/update_service_spec.rb'
- 'ee/spec/services/ee/notification_service_spec.rb'
- 'ee/spec/services/ee/post_receive_service_spec.rb'
@@ -2107,7 +2061,6 @@ Layout/LineLength:
- 'ee/spec/services/epics/update_service_spec.rb'
- 'ee/spec/services/external_status_checks/update_service_spec.rb'
- 'ee/spec/services/geo/blob_download_service_spec.rb'
- - 'ee/spec/services/geo/blob_upload_service_spec.rb'
- 'ee/spec/services/geo/container_repository_sync_spec.rb'
- 'ee/spec/services/geo/framework_repository_sync_service_spec.rb'
- 'ee/spec/services/geo/hashed_storage_attachments_event_store_spec.rb'
@@ -2140,6 +2093,7 @@ Layout/LineLength:
- 'ee/spec/services/jira/requests/issues/list_service_spec.rb'
- 'ee/spec/services/ldap_group_reset_service_spec.rb'
- 'ee/spec/services/members/activate_service_spec.rb'
+ - 'ee/spec/services/merge_requests/create_from_vulnerability_data_service_spec.rb'
- 'ee/spec/services/merge_requests/merge_service_spec.rb'
- 'ee/spec/services/merge_requests/push_options_handler_service_spec.rb'
- 'ee/spec/services/merge_requests/reset_approvals_service_spec.rb'
@@ -2216,7 +2170,6 @@ Layout/LineLength:
- 'ee/spec/services/vulnerability_feedback/create_service_spec.rb'
- 'ee/spec/services/vulnerability_feedback/destroy_service_spec.rb'
- 'ee/spec/services/vulnerability_scanners/list_service_spec.rb'
- - 'ee/spec/services/wiki_pages/destroy_service_spec.rb'
- 'ee/spec/support/features/redacted_search_results_examples.rb'
- 'ee/spec/support/helpers/search_results_helpers.rb'
- 'ee/spec/support/helpers/subscription_portal_helpers.rb'
@@ -2240,19 +2193,16 @@ Layout/LineLength:
- 'ee/spec/support/shared_examples/models/concerns/issuable_links_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/concerns/repository_replicator_strategy_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/concerns/verifiable_replicator_shared_examples.rb'
- - 'ee/spec/support/shared_examples/models/geo_batcher_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/geo_verifiable_registry_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/member_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/protected_environments/authorizable_examples.rb'
- 'ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb'
- - 'ee/spec/support/shared_examples/quick_actions/issuable/assign_shared_examples.rb'
- 'ee/spec/support/shared_examples/quick_actions/issuable/unassign_shared_examples.rb'
- 'ee/spec/support/shared_examples/quick_actions/issue/page_quick_action_shared_examples.rb'
- 'ee/spec/support/shared_examples/quick_actions/merge_request/assign_reviewer_shared_examples.rb'
- 'ee/spec/support/shared_examples/quick_actions/merge_request/unassign_reviewer_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_shared_examples.rb'
- 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb'
- - 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/boards/base_service_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/build_execute_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/ci/play_job_service_shared_examples.rb'
@@ -2342,7 +2292,6 @@ Layout/LineLength:
- 'lib/api/deploy_tokens.rb'
- 'lib/api/deployments.rb'
- 'lib/api/discussions.rb'
- - 'lib/api/entities/system/broadcast_message.rb'
- 'lib/api/entities/application_setting.rb'
- 'lib/api/entities/basic_project_details.rb'
- 'lib/api/entities/branch.rb'
@@ -2548,7 +2497,6 @@ Layout/LineLength:
- 'lib/gitlab/conflict/file.rb'
- 'lib/gitlab/conflict/file_collection.rb'
- 'lib/gitlab/content_security_policy/config_loader.rb'
- - 'lib/gitlab/content_security_policy/directives.rb'
- 'lib/gitlab/current_settings.rb'
- 'lib/gitlab/cycle_analytics/summary/deploy.rb'
- 'lib/gitlab/cycle_analytics/summary/deployment_frequency.rb'
@@ -2599,7 +2547,6 @@ Layout/LineLength:
- 'lib/gitlab/email/handler/create_issue_handler.rb'
- 'lib/gitlab/email/handler/create_merge_request_handler.rb'
- 'lib/gitlab/encrypted_command_base.rb'
- - 'lib/gitlab/encrypted_configuration.rb'
- 'lib/gitlab/endpoint_attributes/config.rb'
- 'lib/gitlab/event_store/event.rb'
- 'lib/gitlab/event_store/store.rb'
@@ -2791,10 +2738,8 @@ Layout/LineLength:
- 'qa/qa/ee/page/project/secure/show.rb'
- 'qa/qa/flow/sign_up.rb'
- 'qa/qa/git/repository.rb'
- - 'qa/qa/page/component/ci_badge_link.rb'
- 'qa/qa/page/component/issuable/sidebar.rb'
- 'qa/qa/page/dashboard/snippet/index.rb'
- - 'qa/qa/page/group/settings/group_deploy_tokens.rb'
- 'qa/qa/page/group/settings/package_registries.rb'
- 'qa/qa/page/merge_request/new.rb'
- 'qa/qa/page/project/import/repo_by_url.rb'
@@ -2818,7 +2763,6 @@ Layout/LineLength:
- 'qa/qa/specs/features/api/1_manage/rate_limits_spec.rb'
- 'qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb'
- 'qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb'
- - 'qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb'
- 'qa/qa/specs/features/api/3_create/repository/files_spec.rb'
- 'qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb'
- 'qa/qa/specs/features/api/3_create/repository/push_postreceive_idempotent_spec.rb'
@@ -2836,9 +2780,7 @@ Layout/LineLength:
- 'qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb'
- - 'qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb'
- - 'qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/repository/branch_with_unusual_name_spec.rb'
@@ -2863,13 +2805,9 @@ Layout/LineLength:
- 'qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb'
- 'qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb'
- - 'qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb'
- 'qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb'
- - 'qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb'
- 'qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb'
- - 'qa/qa/specs/features/browser_ui/4_verify/pipeline/pass_dotenv_variables_to_downstream_via_bridge_spec.rb'
- 'qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb'
- - 'qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb'
- 'qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb'
- 'qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb'
- 'qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb'
@@ -2887,7 +2825,6 @@ Layout/LineLength:
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/license/cloud_activation_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/license/license_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/purchase/user_registration_billing_spec.rb'
- - 'qa/qa/specs/features/ee/browser_ui/13_secure/enable_scanning_from_configuration_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/2_plan/burndown_chart/burndown_chart_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/2_plan/custom_email/custom_email_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/2_plan/epic/epics_management_spec.rb'
@@ -3047,7 +2984,6 @@ Layout/LineLength:
- 'spec/controllers/repositories/git_http_controller_spec.rb'
- 'spec/controllers/repositories/lfs_storage_controller_spec.rb'
- 'spec/controllers/search_controller_spec.rb'
- - 'spec/controllers/sent_notifications_controller_spec.rb'
- 'spec/controllers/sessions_controller_spec.rb'
- 'spec/controllers/uploads_controller_spec.rb'
- 'spec/db/schema_spec.rb'
@@ -3068,7 +3004,6 @@ Layout/LineLength:
- 'spec/factories/namespaces.rb'
- 'spec/factories/notes.rb'
- 'spec/factories/packages/package_files.rb'
- - 'spec/factories/project_members.rb'
- 'spec/factories/projects.rb'
- 'spec/factories/usage_data.rb'
- 'spec/features/action_cable_logging_spec.rb'
@@ -3093,7 +3028,6 @@ Layout/LineLength:
- 'spec/features/calendar_spec.rb'
- 'spec/features/callouts/registration_enabled_spec.rb'
- 'spec/features/commits_spec.rb'
- - 'spec/features/contextual_sidebar_spec.rb'
- 'spec/features/cycle_analytics_spec.rb'
- 'spec/features/dashboard/projects_spec.rb'
- 'spec/features/dashboard/todos/todos_spec.rb'
@@ -3101,7 +3035,6 @@ Layout/LineLength:
- 'spec/features/error_tracking/user_filters_errors_by_status_spec.rb'
- 'spec/features/file_uploads/ci_artifact_spec.rb'
- 'spec/features/file_uploads/maven_package_spec.rb'
- - 'spec/features/file_uploads/multipart_invalid_uploads_spec.rb'
- 'spec/features/frequently_visited_projects_and_groups_spec.rb'
- 'spec/features/groups/board_spec.rb'
- 'spec/features/groups/clusters/user_spec.rb'
@@ -3154,7 +3087,6 @@ Layout/LineLength:
- 'spec/features/merge_request/user_creates_merge_request_spec.rb'
- 'spec/features/merge_request/user_expands_diff_spec.rb'
- 'spec/features/merge_request/user_interacts_with_batched_mr_diffs_spec.rb'
- - 'spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb'
- 'spec/features/merge_request/user_posts_diff_notes_spec.rb'
- 'spec/features/merge_request/user_posts_notes_spec.rb'
- 'spec/features/merge_request/user_resolves_conflicts_spec.rb'
@@ -3188,8 +3120,6 @@ Layout/LineLength:
- 'spec/features/milestones/user_views_milestone_spec.rb'
- 'spec/features/milestones/user_views_milestones_spec.rb'
- 'spec/features/oauth_login_spec.rb'
- - 'spec/features/user_settings/active_sessions_spec.rb'
- - 'spec/features/profiles/password_spec.rb'
- 'spec/features/profiles/two_factor_auths_spec.rb'
- 'spec/features/profiles/user_edit_profile_spec.rb'
- 'spec/features/projects/artifacts/file_spec.rb'
@@ -3263,7 +3193,7 @@ Layout/LineLength:
- 'spec/features/snippets/user_edits_snippet_spec.rb'
- 'spec/features/task_lists_spec.rb'
- 'spec/features/unsubscribe_links_spec.rb'
- - 'spec/features/user_sorts_things_spec.rb'
+ - 'spec/features/user_settings/active_sessions_spec.rb'
- 'spec/features/users/login_spec.rb'
- 'spec/features/users/overview_spec.rb'
- 'spec/features/users/user_browses_projects_on_user_page_spec.rb'
@@ -3300,7 +3230,6 @@ Layout/LineLength:
- 'spec/finders/packages/go/version_finder_spec.rb'
- 'spec/finders/packages/group_packages_finder_spec.rb'
- 'spec/finders/packages/maven/package_finder_spec.rb'
- - 'spec/finders/packages/npm/package_finder_spec.rb'
- 'spec/finders/packages/nuget/package_finder_spec.rb'
- 'spec/finders/packages/packages_finder_spec.rb'
- 'spec/finders/personal_access_tokens_finder_spec.rb'
@@ -3405,7 +3334,6 @@ Layout/LineLength:
- 'spec/helpers/admin/deploy_key_helper_spec.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/helpers/application_settings_helper_spec.rb'
- - 'spec/helpers/auth_helper_spec.rb'
- 'spec/helpers/auto_devops_helper_spec.rb'
- 'spec/helpers/award_emoji_helper_spec.rb'
- 'spec/helpers/blob_helper_spec.rb'
@@ -3488,7 +3416,6 @@ Layout/LineLength:
- 'spec/lib/banzai/filter/broadcast_message_sanitization_filter_spec.rb'
- 'spec/lib/banzai/filter/external_link_filter_spec.rb'
- 'spec/lib/banzai/filter/gollum_tags_filter_spec.rb'
- - 'spec/lib/banzai/filter/image_link_filter_spec.rb'
- 'spec/lib/banzai/filter/inline_diff_filter_spec.rb'
- 'spec/lib/banzai/filter/kroki_filter_spec.rb'
- 'spec/lib/banzai/filter/math_filter_spec.rb'
@@ -3604,7 +3531,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/ci/config/external/file/template_spec.rb'
- 'spec/lib/gitlab/ci/config/external/mapper_spec.rb'
- 'spec/lib/gitlab/ci/config/external/processor_spec.rb'
- - 'spec/lib/gitlab/ci/config/external/rules_spec.rb'
- 'spec/lib/gitlab/ci/config/yaml/tags/reference_spec.rb'
- 'spec/lib/gitlab/ci/cron_parser_spec.rb'
- 'spec/lib/gitlab/ci/parsers/coverage/cobertura_spec.rb'
@@ -3720,7 +3646,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/encoding_helper_spec.rb'
- 'spec/lib/gitlab/encrypted_configuration_spec.rb'
- 'spec/lib/gitlab/error_tracking/processor/grpc_error_processor_spec.rb'
- - 'spec/lib/gitlab/error_tracking/processor/sanitize_error_message_processor_spec.rb'
- 'spec/lib/gitlab/error_tracking/processor/sidekiq_processor_spec.rb'
- 'spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb'
- 'spec/lib/gitlab/etag_caching/router/graphql_spec.rb'
@@ -3729,13 +3654,11 @@ Layout/LineLength:
- 'spec/lib/gitlab/form_builders/gitlab_ui_form_builder_spec.rb'
- 'spec/lib/gitlab/git/base_error_spec.rb'
- 'spec/lib/gitlab/git/commit_spec.rb'
- - 'spec/lib/gitlab/git/compare_spec.rb'
- 'spec/lib/gitlab/git/conflict/file_spec.rb'
- 'spec/lib/gitlab/git/diff_spec.rb'
- 'spec/lib/gitlab/git/raw_diff_change_spec.rb'
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
- 'spec/lib/gitlab/git/repository_spec.rb'
- - 'spec/lib/gitlab/git/tree_spec.rb'
- 'spec/lib/gitlab/git_access_snippet_spec.rb'
- 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb'
@@ -3749,7 +3672,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb'
- 'spec/lib/gitlab/github_import/object_counter_spec.rb'
- - 'spec/lib/gitlab/github_import/user_finder_spec.rb'
- 'spec/lib/gitlab/gl_repository/repo_type_spec.rb'
- 'spec/lib/gitlab/gpg/commit_spec.rb'
- 'spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb'
@@ -3777,12 +3699,10 @@ Layout/LineLength:
- 'spec/lib/gitlab/import_export/import_failure_service_spec.rb'
- 'spec/lib/gitlab/import_export/importer_spec.rb'
- 'spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb'
- - 'spec/lib/gitlab/import_export/json/ndjson_writer_spec.rb'
- 'spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb'
- 'spec/lib/gitlab/import_export/members_mapper_spec.rb'
- 'spec/lib/gitlab/import_export/project/export_task_spec.rb'
- 'spec/lib/gitlab/import_export/project/import_task_spec.rb'
- - 'spec/lib/gitlab/import_export/project/object_builder_spec.rb'
- 'spec/lib/gitlab/import_export/project/relation_factory_spec.rb'
- 'spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
@@ -3803,7 +3723,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/jira_import/labels_importer_spec.rb'
- 'spec/lib/gitlab/jira_import_spec.rb'
- 'spec/lib/gitlab/kas/client_spec.rb'
- - 'spec/lib/gitlab/kas_spec.rb'
- 'spec/lib/gitlab/kubernetes/deployment_spec.rb'
- 'spec/lib/gitlab/kubernetes/kubeconfig/template_spec.rb'
- 'spec/lib/gitlab/kubernetes/kubectl_cmd_spec.rb'
@@ -3826,7 +3745,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/metrics/samplers/threads_sampler_spec.rb'
- 'spec/lib/gitlab/metrics/subscribers/active_record_spec.rb'
- 'spec/lib/gitlab/metrics/subscribers/load_balancing_spec.rb'
- - 'spec/lib/gitlab/metrics/system_spec.rb'
- 'spec/lib/gitlab/metrics/web_transaction_spec.rb'
- 'spec/lib/gitlab/middleware/go_spec.rb'
- 'spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb'
@@ -3907,7 +3825,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb'
- 'spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb'
- - 'spec/lib/gitlab/usage_data_metrics_spec.rb'
- 'spec/lib/gitlab/usage_data_non_sql_metrics_spec.rb'
- 'spec/lib/gitlab/usage_data_queries_spec.rb'
- 'spec/lib/gitlab/usage_data_spec.rb'
@@ -3918,7 +3835,6 @@ Layout/LineLength:
- 'spec/lib/gitlab/utils/usage_data_spec.rb'
- 'spec/lib/gitlab/web_ide/config/entry/global_spec.rb'
- 'spec/lib/gitlab/web_ide/config/entry/terminal_spec.rb'
- - 'spec/lib/gitlab/webpack/file_loader_spec.rb'
- 'spec/lib/gitlab/webpack/manifest_spec.rb'
- 'spec/lib/gitlab/word_diff/parser_spec.rb'
- 'spec/lib/gitlab/workhorse_spec.rb'
@@ -3942,7 +3858,6 @@ Layout/LineLength:
- 'spec/lib/sidebars/projects/menus/ci_cd_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/external_issue_tracker_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/hidden_menu_spec.rb'
- - 'spec/lib/sidebars/projects/menus/monitor_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/packages_registries_menu_spec.rb'
- 'spec/lib/sidebars/projects/menus/security_compliance_menu_spec.rb'
- 'spec/lib/uploaded_file_spec.rb'
@@ -4003,7 +3918,6 @@ Layout/LineLength:
- 'spec/models/concerns/partitioned_table_spec.rb'
- 'spec/models/concerns/pg_full_text_searchable_spec.rb'
- 'spec/models/concerns/project_features_compatibility_spec.rb'
- - 'spec/models/concerns/prometheus_adapter_spec.rb'
- 'spec/models/concerns/resolvable_discussion_spec.rb'
- 'spec/models/concerns/resolvable_note_spec.rb'
- 'spec/models/concerns/routable_spec.rb'
@@ -4017,7 +3931,6 @@ Layout/LineLength:
- 'spec/models/customer_relations/issue_contact_spec.rb'
- 'spec/models/deploy_key_spec.rb'
- 'spec/models/deployment_metrics_spec.rb'
- - 'spec/models/design_management/design_spec.rb'
- 'spec/models/diff_discussion_spec.rb'
- 'spec/models/discussion_spec.rb'
- 'spec/models/environment_spec.rb'
@@ -4080,9 +3993,7 @@ Layout/LineLength:
- 'spec/models/packages/nuget/dependency_link_metadatum_spec.rb'
- 'spec/models/packages/package_file_spec.rb'
- 'spec/models/packages/package_spec.rb'
- - 'spec/models/pages/virtual_domain_spec.rb'
- 'spec/models/personal_access_token_spec.rb'
- - 'spec/models/postgresql/detached_partition_spec.rb'
- 'spec/models/postgresql/replication_slot_spec.rb'
- 'spec/models/preloaders/environments/deployment_preloader_spec.rb'
- 'spec/models/preloaders/group_policy_preloader_spec.rb'
@@ -4095,11 +4006,8 @@ Layout/LineLength:
- 'spec/models/project_spec.rb'
- 'spec/models/project_team_spec.rb'
- 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
- - 'spec/models/projects/repository_storage_move_spec.rb'
- - 'spec/models/projects/topic_spec.rb'
- 'spec/models/projects/triggered_hooks_spec.rb'
- 'spec/models/prometheus_metric_spec.rb'
- - 'spec/models/protected_branch/push_access_level_spec.rb'
- 'spec/models/protected_branch_spec.rb'
- 'spec/models/redirect_route_spec.rb'
- 'spec/models/release_highlight_spec.rb'
@@ -4153,7 +4061,6 @@ Layout/LineLength:
- 'spec/rack_servers/puma_spec.rb'
- 'spec/requests/admin/background_migrations_controller_spec.rb'
- 'spec/requests/api/access_requests_spec.rb'
- - 'spec/requests/api/admin/broadcast_messages_spec.rb'
- 'spec/requests/api/admin/instance_clusters_spec.rb'
- 'spec/requests/api/admin/plan_limits_spec.rb'
- 'spec/requests/api/admin/sidekiq_spec.rb'
@@ -4220,7 +4127,6 @@ Layout/LineLength:
- 'spec/requests/api/graphql/mutations/issues/update_spec.rb'
- 'spec/requests/api/graphql/mutations/jira_import/start_spec.rb'
- 'spec/requests/api/graphql/mutations/merge_requests/set_labels_spec.rb'
- - 'spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb'
- 'spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb'
- 'spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb'
- 'spec/requests/api/graphql/mutations/releases/create_spec.rb'
@@ -4388,7 +4294,6 @@ Layout/LineLength:
- 'spec/services/alert_management/http_integrations/update_service_spec.rb'
- 'spec/services/application_settings/update_service_spec.rb'
- 'spec/services/authorized_project_update/find_records_due_for_refresh_service_spec.rb'
- - 'spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb'
- 'spec/services/boards/issues/create_service_spec.rb'
- 'spec/services/boards/issues/list_service_spec.rb'
- 'spec/services/boards/issues/move_service_spec.rb'
@@ -4472,7 +4377,6 @@ Layout/LineLength:
- 'spec/services/issuable/common_system_notes_service_spec.rb'
- 'spec/services/issuable/destroy_service_spec.rb'
- 'spec/services/issue_links/create_service_spec.rb'
- - 'spec/services/issue_links/list_service_spec.rb'
- 'spec/services/issues/after_create_service_spec.rb'
- 'spec/services/issues/build_service_spec.rb'
- 'spec/services/issues/clone_service_spec.rb'
@@ -4552,7 +4456,6 @@ Layout/LineLength:
- 'spec/services/packages/npm/create_package_service_spec.rb'
- 'spec/services/packages/npm/create_tag_service_spec.rb'
- 'spec/services/packages/nuget/create_dependency_service_spec.rb'
- - 'spec/services/packages/nuget/metadata_extraction_service_spec.rb'
- 'spec/services/packages/nuget/search_service_spec.rb'
- 'spec/services/packages/nuget/update_package_from_metadata_service_spec.rb'
- 'spec/services/packages/rubygems/process_gem_service_spec.rb'
@@ -4583,7 +4486,6 @@ Layout/LineLength:
- 'spec/services/projects/overwrite_project_service_spec.rb'
- 'spec/services/projects/transfer_service_spec.rb'
- 'spec/services/projects/unlink_fork_service_spec.rb'
- - 'spec/services/projects/update_pages_service_spec.rb'
- 'spec/services/projects/update_repository_storage_service_spec.rb'
- 'spec/services/projects/update_service_spec.rb'
- 'spec/services/protected_branches/create_service_spec.rb'
@@ -4618,9 +4520,7 @@ Layout/LineLength:
- 'spec/services/users/approve_service_spec.rb'
- 'spec/services/users/ban_service_spec.rb'
- 'spec/services/users/create_service_spec.rb'
- - 'spec/services/users/reject_service_spec.rb'
- 'spec/services/users/unban_service_spec.rb'
- - 'spec/services/users/upsert_credit_card_validation_service_spec.rb'
- 'spec/services/web_hooks/log_execution_service_spec.rb'
- 'spec/services/work_items/create_and_link_service_spec.rb'
- 'spec/services/work_items/create_from_task_service_spec.rb'
@@ -4628,7 +4528,6 @@ Layout/LineLength:
- 'spec/services/work_items/update_service_spec.rb'
- 'spec/services/x509_certificate_revoke_service_spec.rb'
- 'spec/sidekiq_cluster/sidekiq_cluster_spec.rb'
- - 'spec/simplecov_env.rb'
- 'spec/spec_helper.rb'
- 'spec/support/atlassian/jira_connect/schemata.rb'
- 'spec/support/capybara.rb'
@@ -4696,7 +4595,6 @@ Layout/LineLength:
- 'spec/support/shared_examples/features/manage_applications_shared_examples.rb'
- 'spec/support/shared_examples/features/page_description_shared_examples.rb'
- 'spec/support/shared_examples/features/sidebar/sidebar_milestone_shared_examples.rb'
- - 'spec/support/shared_examples/features/variable_list_shared_examples.rb'
- 'spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb'
- 'spec/support/shared_examples/features/wiki/user_views_wiki_empty_shared_examples.rb'
- 'spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb'
@@ -4848,7 +4746,6 @@ Layout/LineLength:
- 'spec/uploaders/job_artifact_uploader_spec.rb'
- 'spec/uploaders/namespace_file_uploader_spec.rb'
- 'spec/uploaders/object_storage_spec.rb'
- - 'spec/uploaders/pages/deployment_uploader_spec.rb'
- 'spec/validators/import/gitlab_projects/remote_file_validator_spec.rb'
- 'spec/validators/json_schema_validator_spec.rb'
- 'spec/validators/nested_attributes_duplicates_validator_spec.rb'
@@ -4881,7 +4778,6 @@ Layout/LineLength:
- 'spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb'
- 'spec/workers/authorized_project_update/user_refresh_from_replica_worker_spec.rb'
- 'spec/workers/auto_devops/disable_worker_spec.rb'
- - 'spec/workers/bulk_import_worker_spec.rb'
- 'spec/workers/bulk_imports/export_request_worker_spec.rb'
- 'spec/workers/ci/job_artifacts/expire_project_build_artifacts_worker_spec.rb'
- 'spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index 78d1ffac5ac..0fd9bdf250c 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -2299,7 +2299,6 @@ RSpec/ContextWording:
- 'spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb'
- 'spec/requests/api/graphql/mutations/work_items/create_spec.rb'
- 'spec/requests/api/graphql/mutations/work_items/update_spec.rb'
- - 'spec/requests/api/graphql/mutations/work_items/update_task_spec.rb'
- 'spec/requests/api/graphql/namespace_query_spec.rb'
- 'spec/requests/api/graphql/packages/maven_spec.rb'
- 'spec/requests/api/graphql/packages/package_spec.rb'
diff --git a/.rubocop_todo/rspec/expect_change.yml b/.rubocop_todo/rspec/expect_change.yml
index 2b178901b39..c5f56901f5e 100644
--- a/.rubocop_todo/rspec/expect_change.yml
+++ b/.rubocop_todo/rspec/expect_change.yml
@@ -287,7 +287,6 @@ RSpec/ExpectChange:
- 'spec/requests/api/graphql/mutations/work_items/create_spec.rb'
- 'spec/requests/api/graphql/mutations/work_items/delete_spec.rb'
- 'spec/requests/api/graphql/mutations/work_items/update_spec.rb'
- - 'spec/requests/api/graphql/mutations/work_items/update_task_spec.rb'
- 'spec/requests/api/groups_spec.rb'
- 'spec/requests/api/issues/post_projects_issues_spec.rb'
- 'spec/requests/api/labels_spec.rb'
diff --git a/.rubocop_todo/rspec/feature_category.yml b/.rubocop_todo/rspec/feature_category.yml
index 7bcf93cb18a..df29ac4c8bd 100644
--- a/.rubocop_todo/rspec/feature_category.yml
+++ b/.rubocop_todo/rspec/feature_category.yml
@@ -1959,7 +1959,6 @@ RSpec/FeatureCategory:
- 'spec/graphql/mutations/todos/restore_many_spec.rb'
- 'spec/graphql/mutations/todos/restore_spec.rb'
- 'spec/graphql/mutations/user_callouts/create_spec.rb'
- - 'spec/graphql/mutations/work_items/update_task_spec.rb'
- 'spec/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver_spec.rb'
- 'spec/graphql/resolvers/alert_management/alert_resolver_spec.rb'
- 'spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb'
@@ -3559,7 +3558,6 @@ RSpec/FeatureCategory:
- 'spec/lib/gitlab/hook_data/subgroup_builder_spec.rb'
- 'spec/lib/gitlab/hook_data/user_builder_spec.rb'
- 'spec/lib/gitlab/hotlinking_detector_spec.rb'
- - 'spec/lib/gitlab/http_connection_adapter_spec.rb'
- 'spec/lib/gitlab/http_io_spec.rb'
- 'spec/lib/gitlab/i18n/metadata_entry_spec.rb'
- 'spec/lib/gitlab/i18n/po_linter_spec.rb'
diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml
index 2e0e343d868..a14d560a3eb 100644
--- a/.rubocop_todo/rspec/named_subject.yml
+++ b/.rubocop_todo/rspec/named_subject.yml
@@ -2225,7 +2225,6 @@ RSpec/NamedSubject:
- 'spec/lib/gitlab/health_checks/probes/collection_spec.rb'
- 'spec/lib/gitlab/health_checks/redis_spec.rb'
- 'spec/lib/gitlab/hook_data/base_builder_spec.rb'
- - 'spec/lib/gitlab/http_connection_adapter_spec.rb'
- 'spec/lib/gitlab/http_io_spec.rb'
- 'spec/lib/gitlab/import/database_helpers_spec.rb'
- 'spec/lib/gitlab/import/merge_request_creator_spec.rb'
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 91c640ebc10..4589bfedddf 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-14.32.0
+14.33.0
diff --git a/Gemfile b/Gemfile
index 332ce1945ea..5df6c951fff 100644
--- a/Gemfile
+++ b/Gemfile
@@ -336,7 +336,8 @@ gem 'gitlab_chronic_duration', '~> 0.12' # rubocop:todo Gemfile/MissingFeatureCa
gem 'rack-proxy', '~> 0.7.7' # rubocop:todo Gemfile/MissingFeatureCategory
-gem 'sassc-rails', '~> 2.1.0' # rubocop:todo Gemfile/MissingFeatureCategory
+gem 'sassc-rails', '~> 2.1.0', feature_category: :shared, require: false
+gem 'cssbundling-rails', '1.3.3', feature_category: :shared, require: false
gem 'autoprefixer-rails', '10.2.5.1' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'terser', '1.0.2' # rubocop:todo Gemfile/MissingFeatureCategory
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 5e2879887c8..d867f9ff2c9 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -95,6 +95,7 @@
{"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"},
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
{"name":"css_parser","version":"1.14.0","platform":"ruby","checksum":"f2ce6148cd505297b07bdbe7a5db4cce5cf530071f9b732b9a23538d6cdc0113"},
+{"name":"cssbundling-rails","version":"1.3.3","platform":"ruby","checksum":"4aa13311e52a40bc0eb32ca651f44db8df03df273553cf9aeb022570607e1855"},
{"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"},
{"name":"danger","version":"9.3.1","platform":"ruby","checksum":"9070fbac181eb45fb9b69ea25e6ea4faa86796ef33bf8d00346cab4385e51df5"},
{"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
@@ -581,7 +582,7 @@
{"name":"sanitize","version":"6.0.2","platform":"ruby","checksum":"48c4eb8e92bb1699056b6000986ac50fc9df82f458a941abf2c4d6759bccd5cf"},
{"name":"sassc","version":"2.4.0","platform":"ruby","checksum":"4c60a2b0a3b36685c83b80d5789401c2f678c1652e3288315a1551d811d9f83e"},
{"name":"sassc","version":"2.4.0","platform":"x64-mingw32","checksum":"8773b917cb52c7e92c94d4bf324c1c0be3e50d9092f9f5ed4c3c6e454b451c5e"},
-{"name":"sassc-rails","version":"2.1.0","platform":"ruby","checksum":"764dcc74e06930e3483caf0d595084d11f2b0fefd6539abf487cdddfba6cafa2"},
+{"name":"sassc-rails","version":"2.1.2","platform":"ruby","checksum":"5f4fdf3881fc9bdc8e856ffbd9850d70a2878866feae8114aa45996179952db5"},
{"name":"sawyer","version":"0.9.2","platform":"ruby","checksum":"fa3a72d62a4525517b18857ddb78926aab3424de0129be6772a8e2ba240e7aca"},
{"name":"sd_notify","version":"0.1.1","platform":"ruby","checksum":"cbc7ac6caa7cedd26b30a72b5eeb6f36050dc0752df263452ea24fb5a4ad3131"},
{"name":"seed-fu","version":"2.3.7","platform":"ruby","checksum":"f19673443e9af799b730e3d4eca6a89b39e5a36825015dffd00d02ea3365cf74"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 3185c8af8aa..4940a03d49e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -425,6 +425,8 @@ GEM
git
css_parser (1.14.0)
addressable
+ cssbundling-rails (1.3.3)
+ railties (>= 6.0.0)
cvss-suite (3.0.1)
danger (9.3.1)
claide (~> 1.0)
@@ -1511,7 +1513,7 @@ GEM
nokogiri (>= 1.12.0)
sassc (2.4.0)
ffi (~> 1.9)
- sassc-rails (2.1.0)
+ sassc-rails (2.1.2)
railties (>= 4.0.0)
sassc (>= 2.0)
sprockets (> 3.0)
@@ -1843,6 +1845,7 @@ DEPENDENCIES
countries (~> 4.0.0)
creole (~> 0.5.0)
crystalball (~> 0.7.0)
+ cssbundling-rails (= 1.3.3)
csv_builder!
cvss-suite (~> 3.0.1)
database_cleaner-active_record (~> 2.1.0)
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
index 960f28747b0..70fbb9bea42 100644
--- a/app/assets/javascripts/content_editor/services/upload_helpers.js
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -1,3 +1,4 @@
+import { uniqueId } from 'lodash';
import { VARIANT_DANGER } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
@@ -7,17 +8,17 @@ import { ALERT_EVENT } from '../constants';
const chain = (editor) => editor.chain().setMeta('preventAutolink', true);
-const findUploadedFilePosition = (editor, filename) => {
+const findUploadedFilePosition = (editor, fileId) => {
let position;
editor.view.state.doc.descendants((descendant, pos) => {
- if (descendant.attrs.uploading === filename) {
+ if (descendant.attrs.uploading === fileId) {
position = pos;
return false;
}
for (const mark of descendant.marks) {
- if (mark.type.name === 'link' && mark.attrs.uploading === filename) {
+ if (mark.type.name === 'link' && mark.attrs.uploading === fileId) {
position = pos + 1;
return false;
}
@@ -142,11 +143,12 @@ const uploadMedia = async ({ type, editor, file, uploadsPath, renderMarkdown, ev
const objectUrl = URL.createObjectURL(file);
const { selection } = editor.view.state;
const currentNode = selection.$to.node();
+ const fileId = uniqueId(type);
let position = selection.to;
let content = {
type,
- attrs: { uploading: file.name, src: objectUrl, alt: file.name },
+ attrs: { uploading: fileId, src: objectUrl, alt: file.name },
};
let selectionIncrement = 0;
@@ -170,9 +172,9 @@ const uploadMedia = async ({ type, editor, file, uploadsPath, renderMarkdown, ev
})
.then(({ canonicalSrc }) => {
// the position might have changed while uploading, so we need to find it again
- position = findUploadedFilePosition(editor, file.name);
+ position = findUploadedFilePosition(editor, fileId);
- uploadingStates[file.name] = true;
+ uploadingStates[fileId] = true;
editor.view.dispatch(
editor.state.tr.setMeta('preventAutolink', true).setNodeMarkup(position, undefined, {
@@ -186,7 +188,7 @@ const uploadMedia = async ({ type, editor, file, uploadsPath, renderMarkdown, ev
chain(editor).setNodeSelection(position).run();
})
.catch((e) => {
- position = findUploadedFilePosition(editor, file.name);
+ position = findUploadedFilePosition(editor, fileId);
chain(editor)
.deleteRange({ from: position, to: position + 1 })
@@ -203,14 +205,15 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve
const objectUrl = URL.createObjectURL(file);
const { selection } = editor.view.state;
const currentNode = selection.$to.node();
+ const fileId = uniqueId('file');
- uploadingStates[file.name] = true;
+ uploadingStates[fileId] = true;
let position = selection.to;
let content = {
type: 'text',
text: file.name,
- marks: [{ type: 'link', attrs: { href: objectUrl, uploading: file.name } }],
+ marks: [{ type: 'link', attrs: { href: objectUrl, uploading: fileId } }],
};
// if the current node is not empty, we need to wrap the content in a new paragraph
@@ -229,7 +232,7 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve
})
.then(({ src, canonicalSrc }) => {
// the position might have changed while uploading, so we need to find it again
- position = findUploadedFilePosition(editor, file.name);
+ position = findUploadedFilePosition(editor, fileId);
chain(editor)
.setTextSelection(position)
@@ -238,7 +241,7 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve
.run();
})
.catch((e) => {
- position = findUploadedFilePosition(editor, file.name);
+ position = findUploadedFilePosition(editor, fileId);
chain(editor)
.setTextSelection(position)
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.vue b/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.vue
index 89095a55a11..9afed170097 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.vue
@@ -99,15 +99,11 @@ export default {
return this.state.mergeabilityChecks || [];
},
sortedChecks() {
- return [...this.checks]
- .sort((a, b) => {
- if (a.status === 'FAILED' && b.status !== 'FAILED') return -1;
- if (a.status === 'SUCCESS' && b.status !== 'SUCCESS')
- return b.status === 'FAILED' ? 1 : -1;
+ const order = ['FAILED', 'SUCCESS'];
- return 0;
- })
- .filter((s) => s.status !== 'INACTIVE');
+ return [...this.checks]
+ .filter((s) => s.status !== 'INACTIVE')
+ .sort((a, b) => order.indexOf(a.status) - order.indexOf(b.status));
},
failedChecks() {
return this.checks.filter((c) => c.status.toLowerCase() === 'failed');
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js
index d33c0bb4708..ce4a46fe3dd 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js
@@ -76,9 +76,9 @@ export function processFilters(filters) {
type = FILTERED_SEARCH_TERM;
value = token;
} else {
- type = token.type;
- operator = token.value.operator;
- value = token.value.data;
+ type = token?.type;
+ operator = token?.value?.operator;
+ value = token?.value?.data;
}
if (!acc[type]) {
diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb
index 4f61088ab17..8f178174835 100644
--- a/app/controllers/sent_notifications_controller.rb
+++ b/app/controllers/sent_notifications_controller.rb
@@ -11,15 +11,15 @@ class SentNotificationsController < ApplicationController
return render_404 unless unsubscribe_prerequisites_met?
- return unsubscribe_and_redirect if current_user || params[:force]
+ unsubscribe_and_redirect if current_user || params[:force]
end
private
def unsubscribe_prerequisites_met?
@sent_notification.present? &&
- @sent_notification.unsubscribable? &&
- noteable.present?
+ @sent_notification.unsubscribable? &&
+ noteable.present?
end
def noteable
@@ -29,9 +29,7 @@ class SentNotificationsController < ApplicationController
def unsubscribe_and_redirect
noteable.unsubscribe(@sent_notification.recipient, @sent_notification.project)
- if noteable.is_a?(Issue) && @sent_notification.recipient_id == Users::Internal.support_bot.id
- noteable.unsubscribe_email_participant(noteable.external_author)
- end
+ unsubscribe_issue_email_participant
flash[:notice] = _("You have been unsubscribed from this thread.")
@@ -46,6 +44,15 @@ class SentNotificationsController < ApplicationController
end
end
+ def unsubscribe_issue_email_participant
+ return unless noteable.is_a?(Issue)
+ return unless @sent_notification.recipient_id == Users::Internal.support_bot.id
+
+ # Unsubscribe external author for legacy reasons when no issue email participant is set
+ email = @sent_notification.issue_email_participant&.email || noteable.external_author
+ noteable.unsubscribe_email_participant(email)
+ end
+
def noteable_path(noteable)
case noteable
when Issue
diff --git a/app/graphql/mutations/work_items/update_task.rb b/app/graphql/mutations/work_items/update_task.rb
deleted file mode 100644
index d3df235f894..00000000000
--- a/app/graphql/mutations/work_items/update_task.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-module Mutations
- module WorkItems
- class UpdateTask < BaseMutation
- graphql_name 'WorkItemUpdateTask'
- description "Updates a work item's task by Global ID."
-
- include Mutations::SpamProtection
-
- authorize :read_work_item
-
- argument :id, ::Types::GlobalIDType[::WorkItem],
- required: true,
- description: 'Global ID of the work item.'
- argument :task_data, ::Types::WorkItems::UpdatedTaskInputType,
- required: true,
- description: 'Arguments necessary to update a task.'
-
- field :task, Types::WorkItemType,
- null: true,
- description: 'Updated task.'
- field :work_item, Types::WorkItemType,
- null: true,
- description: 'Updated work item.'
-
- def resolve(id:, task_data:)
- task_data_hash = task_data.to_h
- work_item = authorized_find!(id: id)
- task = authorized_find_task!(task_data_hash[:id])
-
- ::WorkItems::UpdateService.new(
- container: task.project,
- current_user: current_user,
- params: task_data_hash.except(:id),
- perform_spam_check: true
- ).execute(task)
-
- check_spam_action_response!(task)
-
- response = { errors: errors_on_object(task) }
-
- if task.valid?
- work_item.expire_etag_cache
-
- response.merge(work_item: work_item, task: task)
- else
- response
- end
- end
-
- private
-
- def authorized_find_task!(task_id)
- task = task_id.find
-
- if current_user.can?(:update_work_item, task)
- task
- else
- # Fail early if user cannot update task
- raise_resource_not_available_error!
- end
- end
-
- def find_object(id:)
- id.find
- end
- end
- end
-end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 51ab6880b1a..94bb3055bc4 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -191,7 +191,6 @@ module Types
mount_mutation Mutations::WorkItems::CreateFromTask, alpha: { milestone: '15.1' }
mount_mutation Mutations::WorkItems::Delete, alpha: { milestone: '15.1' }
mount_mutation Mutations::WorkItems::Update, alpha: { milestone: '15.1' }
- mount_mutation Mutations::WorkItems::UpdateTask, alpha: { milestone: '15.1' }
mount_mutation Mutations::WorkItems::Export, alpha: { milestone: '15.10' }
mount_mutation Mutations::WorkItems::Convert, alpha: { milestone: '15.11' }
mount_mutation Mutations::WorkItems::LinkedItems::Add, alpha: { milestone: '16.3' }
diff --git a/app/graphql/types/work_items/updated_task_input_type.rb b/app/graphql/types/work_items/updated_task_input_type.rb
deleted file mode 100644
index 9f8afa2ff1b..00000000000
--- a/app/graphql/types/work_items/updated_task_input_type.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-module Types
- module WorkItems
- class UpdatedTaskInputType < BaseInputObject
- graphql_name 'WorkItemUpdatedTaskInput'
-
- include Mutations::WorkItems::UpdateArguments
- end
- end
-end
diff --git a/app/mailers/emails/service_desk.rb b/app/mailers/emails/service_desk.rb
index 64e6122f9c7..58890fd29c5 100644
--- a/app/mailers/emails/service_desk.rb
+++ b/app/mailers/emails/service_desk.rb
@@ -37,7 +37,7 @@ module Emails
def service_desk_new_note_email(issue_id, note_id, recipient)
@note = Note.find(note_id)
- setup_service_desk_mail(issue_id)
+ setup_service_desk_mail(issue_id, recipient)
# Prepare uploads for text replacement in markdown content
setup_service_desk_attachments
@@ -49,7 +49,7 @@ module Emails
options = {
from: email_sender,
- to: recipient,
+ to: recipient.email,
subject: subject_base,
**service_desk_template_content_options('new_note')
}
@@ -119,14 +119,20 @@ module Emails
private
- def setup_service_desk_mail(issue_id)
+ def setup_service_desk_mail(issue_id, issue_email_participant = nil)
@issue = Issue.find(issue_id)
@project = @issue.project
@support_bot = Users::Internal.support_bot
@service_desk_setting = @project.service_desk_setting
- @sent_notification = SentNotification.record(@issue, @support_bot.id, reply_key)
+ if issue_email_participant.blank? && @issue.external_author.present?
+ issue_email_participant = @issue.issue_email_participants.find_by_email(@issue.external_author)
+ end
+
+ @sent_notification = SentNotification.record(@issue, @support_bot.id, reply_key, {
+ issue_email_participant: issue_email_participant
+ })
end
def service_desk_template_content_options(email_type)
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index c3987d85381..c7d6f2843de 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -243,8 +243,9 @@ class NotifyPreview < ActionMailer::Preview
def service_desk_new_note_email
cleanup do
note = create_note(noteable_type: 'Issue', noteable_id: issue.id, note: 'Issue note content')
+ participant = IssueEmailParticipant.create!(issue: issue, email: 'user@example.com')
- Notify.service_desk_new_note_email(issue.id, note.id, 'someone@gitlab.com').message
+ Notify.service_desk_new_note_email(issue.id, note.id, participant).message
end
end
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index f3a0479d3b7..66da5369d38 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -4,6 +4,7 @@ class SentNotification < ApplicationRecord
belongs_to :project
belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :recipient, class_name: "User"
+ belongs_to :issue_email_participant
validates :recipient, presence: true
validates :reply_key, presence: true, uniqueness: true
diff --git a/app/models/work_items/widgets/base.rb b/app/models/work_items/widgets/base.rb
index c4e87decdbf..a3051f17158 100644
--- a/app/models/work_items/widgets/base.rb
+++ b/app/models/work_items/widgets/base.rb
@@ -15,10 +15,18 @@ module WorkItems
[]
end
+ def self.sync_params
+ []
+ end
+
def self.process_quick_action_param(param_name, value)
{ param_name => value }
end
+ def self.process_sync_params(params)
+ params
+ end
+
def self.callback_class
WorkItems::Callbacks.const_get(name.demodulize, false)
rescue NameError
diff --git a/app/models/work_items/widgets/hierarchy.rb b/app/models/work_items/widgets/hierarchy.rb
index fc6714f1e08..1d888dd71a8 100644
--- a/app/models/work_items/widgets/hierarchy.rb
+++ b/app/models/work_items/widgets/hierarchy.rb
@@ -23,6 +23,10 @@ module WorkItems
[:set_parent, :add_child]
end
+ def self.sync_params
+ [:parent]
+ end
+
def self.process_quick_action_param(param_name, value)
return super unless param_name.in?(quick_action_params) && value.present?
@@ -30,6 +34,16 @@ module WorkItems
return { children: value } if param_name == :add_child
end
+
+ def self.process_sync_params(params)
+ parent_param = params.fetch(:parent, nil)
+
+ if parent_param&.work_item
+ { parent: parent_param.work_item }
+ else
+ {}
+ end
+ end
end
end
end
diff --git a/app/models/work_items/widgets/labels.rb b/app/models/work_items/widgets/labels.rb
index e8b36156fec..0b5a231deff 100644
--- a/app/models/work_items/widgets/labels.rb
+++ b/app/models/work_items/widgets/labels.rb
@@ -13,6 +13,10 @@ module WorkItems
def self.quick_action_params
[:add_label_ids, :remove_label_ids, :label_ids]
end
+
+ def self.sync_params
+ [:label_ids]
+ end
end
end
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 6ec0a46518a..cef97a42f11 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -243,6 +243,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :destroy_deploy_token
enable :update_runners_registration_token
enable :owner_access
+ enable :update_git_access_protocol
enable :read_billing
enable :edit_billing
diff --git a/app/services/click_house/sync_strategies/base_sync_strategy.rb b/app/services/click_house/sync_strategies/base_sync_strategy.rb
index 58c2161b83c..54f0f084d05 100644
--- a/app/services/click_house/sync_strategies/base_sync_strategy.rb
+++ b/app/services/click_house/sync_strategies/base_sync_strategy.rb
@@ -41,7 +41,7 @@ module ClickHouse
private
def enabled?
- ClickHouse::Client.database_configured?(:main)
+ Gitlab::ClickHouse.configured?
end
def context
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 0240d0184ac..27c52fc7303 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -227,6 +227,7 @@ class IssuableBaseService < ::BaseContainerService
def create(issuable, skip_system_notes: false)
initialize_callbacks!(issuable)
+ prepare_create_params(issuable)
handle_quick_actions(issuable)
filter_params(issuable)
@@ -289,6 +290,10 @@ class IssuableBaseService < ::BaseContainerService
# To be overridden by subclasses
end
+ def prepare_create_params(issuable)
+ # To be overridden by subclasses
+ end
+
def after_update(issuable, old_associations)
handle_description_updated(issuable)
handle_label_changes(issuable, old_associations[:labels])
diff --git a/app/services/namespace_settings/update_service.rb b/app/services/namespace_settings/update_service.rb
index 92766bc0267..f6f59738d44 100644
--- a/app/services/namespace_settings/update_service.rb
+++ b/app/services/namespace_settings/update_service.rb
@@ -31,6 +31,10 @@ module NamespaceSettings
param_key: :default_branch_protection_defaults,
user_policy: :update_default_branch_protection
)
+ validate_settings_param_for_root_group(
+ param_key: :enabled_git_access_protocol,
+ user_policy: :update_git_access_protocol
+ )
handle_default_branch_protection unless settings_params[:default_branch_protection].blank?
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 36431c1cbde..3c40707d0c6 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -446,14 +446,18 @@ class NotificationService
return unless note.project.service_desk_enabled?
issue = note.noteable
- recipients = issue.email_participants_emails
+ recipients = issue.issue_email_participants
return unless recipients.any?
- support_bot = Users::Internal.support_bot
- recipients.delete(issue.external_author) if note.author == support_bot
+ # Only populated if note is from external participant
+ note_external_author = note.note_metadata&.email_participant&.downcase
recipients.each do |recipient|
+ # Don't send Service Desk notification if the recipient is the author of the note.
+ # We store emails as-is but compare downcased versions.
+ next if recipient.email.downcase == note_external_author
+
mailer.service_desk_new_note_email(issue.id, note.id, recipient).deliver_later
Gitlab::Metrics::BackgroundTransaction.current&.add_event(:service_desk_new_note_email)
end
diff --git a/app/services/work_items/create_service.rb b/app/services/work_items/create_service.rb
index f9eadc3fb60..e1e6063c8ac 100644
--- a/app/services/work_items/create_service.rb
+++ b/app/services/work_items/create_service.rb
@@ -53,6 +53,21 @@ module WorkItems
end
end
+ def prepare_create_params(work_item)
+ execute_widgets(
+ work_item: work_item,
+ callback: :prepare_create_params,
+ widget_params: @widget_params,
+ service_params: params
+ )
+
+ super
+ end
+
+ def parent
+ container
+ end
+
private
override :handle_quick_actions
diff --git a/app/services/work_items/widgets/labels_service/base_service.rb b/app/services/work_items/widgets/labels_service/base_service.rb
new file mode 100644
index 00000000000..2d679c1f18c
--- /dev/null
+++ b/app/services/work_items/widgets/labels_service/base_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module LabelsService
+ class BaseService < WorkItems::Widgets::BaseService
+ private
+
+ def prepare_params(params: {}, permitted_params: [])
+ clear_label_params(params) if new_type_excludes_widget?
+
+ return if params.blank?
+ return unless has_permission?(:set_work_item_metadata)
+
+ service_params.merge!(params.slice(*permitted_params))
+ end
+
+ def clear_label_params(params)
+ params[:remove_label_ids] = @work_item.labels.map(&:id)
+ params[:add_label_ids] = []
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/work_items/widgets/labels_service/create_service.rb b/app/services/work_items/widgets/labels_service/create_service.rb
new file mode 100644
index 00000000000..bed6be173cc
--- /dev/null
+++ b/app/services/work_items/widgets/labels_service/create_service.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module LabelsService
+ class CreateService < BaseService
+ def prepare_create_params(params: {})
+ prepare_params(params: params, permitted_params: %i[add_label_ids remove_label_ids label_ids])
+ end
+
+ def clear_label_params(params)
+ params[:add_label_ids] = []
+ params[:label_ids] = []
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/work_items/widgets/labels_service/update_service.rb b/app/services/work_items/widgets/labels_service/update_service.rb
index b0791571924..780451e3eae 100644
--- a/app/services/work_items/widgets/labels_service/update_service.rb
+++ b/app/services/work_items/widgets/labels_service/update_service.rb
@@ -3,17 +3,9 @@
module WorkItems
module Widgets
module LabelsService
- class UpdateService < WorkItems::Widgets::BaseService
+ class UpdateService < BaseService
def prepare_update_params(params: {})
- if new_type_excludes_widget?
- params[:remove_label_ids] = @work_item.labels.map(&:id)
- params[:add_label_ids] = []
- end
-
- return if params.blank?
- return unless has_permission?(:set_work_item_metadata)
-
- service_params.merge!(params.slice(:add_label_ids, :remove_label_ids))
+ prepare_params(params: params, permitted_params: %i[add_label_ids remove_label_ids])
end
end
end
diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml
index 68de9c44e38..2f2f67ce3cd 100644
--- a/app/views/projects/issues/_new_branch.html.haml
+++ b/app/views/projects/issues/_new_branch.html.haml
@@ -48,18 +48,17 @@
%label{ for: 'new-branch-name' }
= _('Branch name')
%input#new-branch-name.js-branch-name.form-control.gl-form-input{ type: 'text', placeholder: "#{@issue.to_branch_name}", value: "#{@issue.to_branch_name}" }
- %span.js-branch-message.form-text
+ %span.js-branch-message.form-text.gl-font-sm
.form-group
%label{ for: 'source-name' }
= _('Source (branch or tag)')
%input#source-name.js-ref.ref.form-control.gl-form-input{ type: 'text', placeholder: "#{@project.default_branch}", value: "#{@project.default_branch}", data: { value: "#{@project.default_branch}" } }
- %span.js-ref-message.form-text
+ %span.js-ref-message.form-text.gl-font-sm
- .form-group
- = render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'js-create-target', data: { action: 'create-mr' } }) do
- = create_mr_text
+ = render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'js-create-target', data: { action: 'create-mr' } }) do
+ = create_mr_text
- if can_create_confidential_merge_request?
- %p.gl-text-orange-500.js-exposed-info-warning.gl-display-none
+ %p.gl-text-orange-500.gl-font-sm.js-exposed-info-warning.gl-display-none
= _('This may expose confidential information as the selected fork is in another namespace that can have other members.')
diff --git a/app/workers/click_house/concerns/consistency_worker.rb b/app/workers/click_house/concerns/consistency_worker.rb
index 5fa1608ea2f..3ed0188ba88 100644
--- a/app/workers/click_house/concerns/consistency_worker.rb
+++ b/app/workers/click_house/concerns/consistency_worker.rb
@@ -66,7 +66,7 @@ module ClickHouse
end
def enabled?
- ClickHouse::Client.database_configured?(:main) && Feature.enabled?(:event_sync_worker_for_click_house)
+ Gitlab::ClickHouse.configured? && Feature.enabled?(:event_sync_worker_for_click_house)
end
def runtime_limiter
diff --git a/config/application.rb b/config/application.rb
index 0634bbf5165..bdcb544d9b4 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -11,6 +11,7 @@ require 'action_view/railtie'
require 'action_mailer/railtie'
require 'action_cable/engine'
require 'rails/test_unit/railtie'
+require 'sprockets/railtie'
require 'gitlab/utils/all'
@@ -254,6 +255,19 @@ module Gitlab
config.active_record.has_many_inversing = false
config.active_record.belongs_to_required_by_default = false
+ # Switch between cssbundling-rails and sassc-rails conditionally
+ # To activate cssbundling-rails you can set `USE_NEW_CSS_PIPELINE=1`
+ # For more context, see: https://gitlab.com/gitlab-org/gitlab/-/issues/438278
+ # Need to be loaded before initializers
+ config.before_configuration do
+ if Gitlab::Utils.to_boolean(ENV["USE_NEW_CSS_PIPELINE"])
+ require 'cssbundling-rails'
+ else
+ require 'fileutils'
+ require 'sassc-rails'
+ end
+ end
+
# Enable the asset pipeline
config.assets.enabled = true
@@ -542,7 +556,7 @@ module Gitlab
# sprocket-rails adds some precompile assets we actually do not need.
#
- # It copies all _non_ js and CSS files from the app/assets/ older.
+ # It copies all _non_ js and CSS files from the app/assets/ folder.
#
# In our case this copies for example: Vue, Markdown and Graphql, which we do not need
# for production.
@@ -606,6 +620,14 @@ module Gitlab
end
end
+ # Add `app/assets/builds` as the highest precedence to find assets
+ # This is required if cssbundling-rails is used, but should not affect sassc-rails. it would be empty
+ if defined?(Cssbundling)
+ initializer :add_cssbundling_output_dir, after: :prefer_specialized_assets do |app|
+ app.config.assets.paths.unshift("#{config.root}/app/assets/builds")
+ end
+ end
+
# We run the contents of active_record.clear_active_connections again
# because we connect to database from routes
# https://github.com/rails/rails/blob/fdf840f69a2e33d78a9d40b91d9b7fddb76711e9/activerecord/lib/active_record/railtie.rb#L308
diff --git a/config/initializers_before_autoloader/004_zeitwerk.rb b/config/initializers_before_autoloader/004_zeitwerk.rb
index 2d54ab87dca..f7dafb8dbde 100644
--- a/config/initializers_before_autoloader/004_zeitwerk.rb
+++ b/config/initializers_before_autoloader/004_zeitwerk.rb
@@ -35,7 +35,6 @@ Rails.autoloaders.each do |autoloader|
'html_parser' => 'HTMLParser',
'html_gitlab' => 'HTMLGitlab',
'http' => 'HTTP',
- 'http_connection_adapter' => 'HTTPConnectionAdapter',
'http_clone_enabled_check' => 'HTTPCloneEnabledCheck',
'hangouts_chat_http_override' => 'HangoutsChatHTTPOverride',
'chunked_io' => 'ChunkedIO',
diff --git a/db/docs/ci_freeze_periods.yml b/db/docs/ci_freeze_periods.yml
index 0267f925149..4a64dcd44f8 100644
--- a/db/docs/ci_freeze_periods.yml
+++ b/db/docs/ci_freeze_periods.yml
@@ -8,3 +8,5 @@ description: https://docs.gitlab.com/ee/ci/environments/deployment_safety.html#p
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29162
milestone: '13.0'
gitlab_schema: gitlab_ci
+sharding_key:
+ project_id: projects
diff --git a/db/docs/ci_resource_groups.yml b/db/docs/ci_resource_groups.yml
index ea66284ccd1..480fddb6e08 100644
--- a/db/docs/ci_resource_groups.yml
+++ b/db/docs/ci_resource_groups.yml
@@ -8,3 +8,5 @@ description: https://docs.gitlab.com/ee/ci/resource_groups/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20950
milestone: '12.7'
gitlab_schema: gitlab_ci
+sharding_key:
+ project_id: projects
diff --git a/db/docs/deploy_keys_projects.yml b/db/docs/deploy_keys_projects.yml
index 5d3591f1b4f..7c63d8c41e3 100644
--- a/db/docs/deploy_keys_projects.yml
+++ b/db/docs/deploy_keys_projects.yml
@@ -7,4 +7,12 @@ feature_categories:
description: https://docs.gitlab.com/ee/user/project/deploy_keys/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/a735ce2aa7da72242629a4452c33e7a1900fdd62
milestone: "<6.0"
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/deployments.yml b/db/docs/deployments.yml
index 3fc477efced..113d0816669 100644
--- a/db/docs/deployments.yml
+++ b/db/docs/deployments.yml
@@ -4,9 +4,16 @@ classes:
- Deployment
feature_categories:
- continuous_delivery
-description: >-
- Stores metadata related to a deployment CI Build, including user, environment, status, and SHA.
- See https://docs.gitlab.com/ee/ci/environments/ for more details.
+description: Stores metadata related to a deployment CI Build, including user, environment,
+ status, and SHA. See https://docs.gitlab.com/ee/ci/environments/ for more details.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/907c0e6796b69f9577c147dd489cf55748c749ac
milestone: '8.9'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/dora_configurations.yml b/db/docs/dora_configurations.yml
index 63114ba6f80..6268660158a 100644
--- a/db/docs/dora_configurations.yml
+++ b/db/docs/dora_configurations.yml
@@ -7,4 +7,12 @@ feature_categories:
description: Stores project specific configurations for DORA4 calculations.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96561
milestone: '15.4'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/environments.yml b/db/docs/environments.yml
index d7fcce52898..36abfc31e97 100644
--- a/db/docs/environments.yml
+++ b/db/docs/environments.yml
@@ -4,9 +4,16 @@ classes:
- Environment
feature_categories:
- continuous_delivery
-description: >-
- Project-level deployment target and metadata.
- See https://docs.gitlab.com/ee/ci/environments/ for more details.
+description: Project-level deployment target and metadata. See https://docs.gitlab.com/ee/ci/environments/
+ for more details.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/907c0e6796b69f9577c147dd489cf55748c749ac
milestone: '8.9'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/docs/group_deploy_keys_groups.yml b/db/docs/group_deploy_keys_groups.yml
index 129be2af5df..615f30384b3 100644
--- a/db/docs/group_deploy_keys_groups.yml
+++ b/db/docs/group_deploy_keys_groups.yml
@@ -7,4 +7,12 @@ feature_categories:
description: https://docs.gitlab.com/ee/user/project/deploy_keys/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32901
milestone: '13.2'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ group_id: namespaces
diff --git a/db/docs/group_deploy_tokens.yml b/db/docs/group_deploy_tokens.yml
index 450f67c57b1..bdc22d32061 100644
--- a/db/docs/group_deploy_tokens.yml
+++ b/db/docs/group_deploy_tokens.yml
@@ -7,4 +7,12 @@ feature_categories:
description: https://docs.gitlab.com/ee/user/project/deploy_tokens/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23460
milestone: '12.8'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ group_id: namespaces
diff --git a/db/docs/project_deploy_tokens.yml b/db/docs/project_deploy_tokens.yml
index 80bca84bf4c..fe8d896ddbc 100644
--- a/db/docs/project_deploy_tokens.yml
+++ b/db/docs/project_deploy_tokens.yml
@@ -7,4 +7,12 @@ feature_categories:
description: https://docs.gitlab.com/ee/user/project/deploy_tokens/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/8315861c9a50675b4f4f4ca536f0da90f27994f3
milestone: '10.7'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
+allow_cross_joins:
+- gitlab_main_clusterwide
+allow_cross_transactions:
+- gitlab_main_clusterwide
+allow_cross_foreign_keys:
+- gitlab_main_clusterwide
+sharding_key:
+ project_id: projects
diff --git a/db/migrate/20240104092321_add_issue_email_participant_id_to_sent_notifications.rb b/db/migrate/20240104092321_add_issue_email_participant_id_to_sent_notifications.rb
new file mode 100644
index 00000000000..9b5d7612b00
--- /dev/null
+++ b/db/migrate/20240104092321_add_issue_email_participant_id_to_sent_notifications.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddIssueEmailParticipantIdToSentNotifications < Gitlab::Database::Migration[2.2]
+ milestone '16.9'
+
+ def change
+ add_column :sent_notifications, :issue_email_participant_id, :bigint, null: true
+ end
+end
diff --git a/db/migrate/20240104142200_add_index_sent_notifications_on_issue_email_participant_id.rb b/db/migrate/20240104142200_add_index_sent_notifications_on_issue_email_participant_id.rb
new file mode 100644
index 00000000000..c9b75529470
--- /dev/null
+++ b/db/migrate/20240104142200_add_index_sent_notifications_on_issue_email_participant_id.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexSentNotificationsOnIssueEmailParticipantId < Gitlab::Database::Migration[2.2]
+ disable_ddl_transaction!
+
+ milestone '16.9'
+
+ INDEX_NAME = 'index_sent_notifications_on_issue_email_participant_id'
+
+ def up
+ add_concurrent_index :sent_notifications, :issue_email_participant_id, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :sent_notifications, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20240104142216_add_fk_on_sent_notifications_to_issue_email_participants.rb b/db/migrate/20240104142216_add_fk_on_sent_notifications_to_issue_email_participants.rb
new file mode 100644
index 00000000000..c3f1a28ded3
--- /dev/null
+++ b/db/migrate/20240104142216_add_fk_on_sent_notifications_to_issue_email_participants.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class AddFkOnSentNotificationsToIssueEmailParticipants < Gitlab::Database::Migration[2.2]
+ disable_ddl_transaction!
+
+ milestone '16.9'
+
+ def up
+ add_concurrent_foreign_key(
+ :sent_notifications,
+ :issue_email_participants,
+ column: :issue_email_participant_id,
+ on_delete: :nullify,
+ validate: false
+ )
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :sent_notifications, column: :issue_email_participant_id
+ end
+ end
+end
diff --git a/db/schema_migrations/20240104092321 b/db/schema_migrations/20240104092321
new file mode 100644
index 00000000000..a0250e57bab
--- /dev/null
+++ b/db/schema_migrations/20240104092321
@@ -0,0 +1 @@
+947ad53db5666956141f4fe05ba0d49377720b481e88b5b9057302dc6670b1af \ No newline at end of file
diff --git a/db/schema_migrations/20240104142200 b/db/schema_migrations/20240104142200
new file mode 100644
index 00000000000..e491d148e96
--- /dev/null
+++ b/db/schema_migrations/20240104142200
@@ -0,0 +1 @@
+97d3dccf21797a0fb1077c93a85691f6c29d3ad0492da6795521bc63dae3cb56 \ No newline at end of file
diff --git a/db/schema_migrations/20240104142216 b/db/schema_migrations/20240104142216
new file mode 100644
index 00000000000..866f82e926d
--- /dev/null
+++ b/db/schema_migrations/20240104142216
@@ -0,0 +1 @@
+26d307bd716dfea4803f877182a9891dfcc4af4997f62cb91e430d7fcd7ac2c8 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 7584786bd31..14b6be62159 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -23901,7 +23901,8 @@ CREATE TABLE sent_notifications (
commit_id character varying,
reply_key character varying NOT NULL,
in_reply_to_discussion_id character varying,
- id bigint NOT NULL
+ id bigint NOT NULL,
+ issue_email_participant_id bigint
);
CREATE SEQUENCE sent_notifications_id_seq
@@ -35360,6 +35361,8 @@ CREATE UNIQUE INDEX index_security_trainings_on_unique_project_id ON security_tr
CREATE INDEX index_self_managed_prometheus_alert_events_on_environment_id ON self_managed_prometheus_alert_events USING btree (environment_id);
+CREATE INDEX index_sent_notifications_on_issue_email_participant_id ON sent_notifications USING btree (issue_email_participant_id);
+
CREATE INDEX index_sent_notifications_on_noteable_type_noteable_id ON sent_notifications USING btree (noteable_id) WHERE ((noteable_type)::text = 'Issue'::text);
CREATE UNIQUE INDEX index_sent_notifications_on_reply_key ON sent_notifications USING btree (reply_key);
@@ -38614,6 +38617,9 @@ ALTER TABLE ONLY issue_customer_relations_contacts
ALTER TABLE ONLY ssh_signatures
ADD CONSTRAINT fk_7d2f93996c FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY sent_notifications
+ ADD CONSTRAINT fk_7d7663e36a FOREIGN KEY (issue_email_participant_id) REFERENCES issue_email_participants(id) ON DELETE SET NULL NOT VALID;
+
ALTER TABLE ONLY labels
ADD CONSTRAINT fk_7de4989a69 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md
index eb620ff7413..d492d3d32b3 100644
--- a/doc/administration/gitaly/configure_gitaly.md
+++ b/doc/administration/gitaly/configure_gitaly.md
@@ -136,16 +136,14 @@ To avoid downtime while rotating the Gitaly token, you can temporarily disable a
Gitaly and GitLab use two shared secrets for authentication:
-- _Gitaly token_: used to authenticate gRPC requests to Gitaly
-- _GitLab Shell token_: used for authentication callbacks from GitLab Shell to the GitLab internal API
-
-Configure authentication in one of two ways:
+- _Gitaly token_: used to authenticate gRPC requests to Gitaly.
+- _GitLab Shell token_: used for authentication callbacks from GitLab Shell to the GitLab internal API.
::Tabs
:::TabTitle Linux package (Omnibus)
-To configure the _Gitaly token_, edit `/etc/gitlab/gitlab.rb`:
+1. To configure the _Gitaly token_, edit `/etc/gitlab/gitlab.rb`:
```ruby
gitaly['configuration'] = {
@@ -157,20 +155,20 @@ To configure the _Gitaly token_, edit `/etc/gitlab/gitlab.rb`:
}
```
-Configure the _GitLab Shell token_ in one of two ways.
+1. Configure the _GitLab Shell token_ in one of two ways:
-Method 1 (recommended):
+ - Method 1 (recommended):
-Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly servers
- (and any other Gitaly clients).
+ Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly servers
+ (and any other Gitaly clients).
-Method 2:
+ - Method 2:
-Edit `/etc/gitlab/gitlab.rb`:
+ Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_shell['secret_token'] = 'shellsecret'
- ```
+ ```ruby
+ gitlab_shell['secret_token'] = 'shellsecret'
+ ```
:::TabTitle Self-compiled (source)
@@ -206,7 +204,7 @@ Updates to example must be made at:
- All reference architecture pages
-->
-Configure Gitaly server in one of two ways:
+Configure Gitaly server.
::Tabs
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index ab52f1ceb2a..584bdb3526a 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -8741,33 +8741,6 @@ Input type: `WorkItemUpdateInput`
| <a id="mutationworkitemupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationworkitemupdateworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. |
-### `Mutation.workItemUpdateTask`
-
-Updates a work item's task by Global ID.
-
-WARNING:
-**Introduced** in 15.1.
-This feature is an Experiment. It can be changed or removed at any time.
-
-Input type: `WorkItemUpdateTaskInput`
-
-#### Arguments
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="mutationworkitemupdatetaskclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| <a id="mutationworkitemupdatetaskid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
-| <a id="mutationworkitemupdatetasktaskdata"></a>`taskData` | [`WorkItemUpdatedTaskInput!`](#workitemupdatedtaskinput) | Arguments necessary to update a task. |
-
-#### Fields
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="mutationworkitemupdatetaskclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
-| <a id="mutationworkitemupdatetaskerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
-| <a id="mutationworkitemupdatetasktask"></a>`task` | [`WorkItem`](#workitem) | Updated task. |
-| <a id="mutationworkitemupdatetaskworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. |
-
### `Mutation.workspaceCreate`
WARNING:
@@ -34787,27 +34760,6 @@ Attributes for value stream stage.
| <a id="workitemconverttaskinputtitle"></a>`title` | [`String!`](#string) | Full string of the task to be replaced. New title for the created work item. |
| <a id="workitemconverttaskinputworkitemtypeid"></a>`workItemTypeId` | [`WorkItemsTypeID!`](#workitemstypeid) | Global ID of the work item type used to create the new work item. |
-### `WorkItemUpdatedTaskInput`
-
-#### Arguments
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="workitemupdatedtaskinputassigneeswidget"></a>`assigneesWidget` | [`WorkItemWidgetAssigneesInput`](#workitemwidgetassigneesinput) | Input for assignees widget. |
-| <a id="workitemupdatedtaskinputawardemojiwidget"></a>`awardEmojiWidget` | [`WorkItemWidgetAwardEmojiUpdateInput`](#workitemwidgetawardemojiupdateinput) | Input for emoji reactions widget. |
-| <a id="workitemupdatedtaskinputconfidential"></a>`confidential` | [`Boolean`](#boolean) | Sets the work item confidentiality. |
-| <a id="workitemupdatedtaskinputcurrentusertodoswidget"></a>`currentUserTodosWidget` | [`WorkItemWidgetCurrentUserTodosInput`](#workitemwidgetcurrentusertodosinput) | Input for to-dos widget. |
-| <a id="workitemupdatedtaskinputdescriptionwidget"></a>`descriptionWidget` | [`WorkItemWidgetDescriptionInput`](#workitemwidgetdescriptioninput) | Input for description widget. |
-| <a id="workitemupdatedtaskinputhierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyUpdateInput`](#workitemwidgethierarchyupdateinput) | Input for hierarchy widget. |
-| <a id="workitemupdatedtaskinputid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
-| <a id="workitemupdatedtaskinputlabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. |
-| <a id="workitemupdatedtaskinputmilestonewidget"></a>`milestoneWidget` | [`WorkItemWidgetMilestoneInput`](#workitemwidgetmilestoneinput) | Input for milestone widget. |
-| <a id="workitemupdatedtaskinputnoteswidget"></a>`notesWidget` | [`WorkItemWidgetNotesInput`](#workitemwidgetnotesinput) | Input for notes widget. |
-| <a id="workitemupdatedtaskinputnotificationswidget"></a>`notificationsWidget` | [`WorkItemWidgetNotificationsUpdateInput`](#workitemwidgetnotificationsupdateinput) | Input for notifications widget. |
-| <a id="workitemupdatedtaskinputstartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. |
-| <a id="workitemupdatedtaskinputstateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. |
-| <a id="workitemupdatedtaskinputtitle"></a>`title` | [`String`](#string) | Title of the work item. |
-
### `WorkItemWidgetAssigneesInput`
#### Arguments
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 90820727040..2cfe6e0ead7 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -520,7 +520,7 @@ Example response:
Get all details of a group. This endpoint can be accessed without authentication
if the group is publicly accessible. In case the user that requests is an administrator
-if the group is publicly accessible. With authentication, it returns the `runners_token`
+if the group is publicly accessible. With authentication, it returns the `runners_token` and `enabled_git_access_protocol`
for the group too, if the user is an administrator or group owner.
```plaintext
@@ -568,6 +568,7 @@ Example response:
"runners_token": "ba324ca7b1c77fc20bb9",
"file_template_project_id": 1,
"parent_id": null,
+ "enabled_git_access_protocol": "all",
"created_at": "2020-01-15T12:36:29.590Z",
"shared_with_groups": [
{
@@ -829,6 +830,7 @@ Parameters:
| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). Default to the global level default branch protection setting. |
| `default_branch_protection_defaults` | hash | no | See [Options for `default_branch_protection_defaults`](#options-for-default_branch_protection_defaults). |
| `description` | string | no | The group's description. |
+| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `all` to allow both protocols. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/436618) in GitLab 16.9. |
| `emails_disabled` | boolean | no | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127899) in GitLab 16.5.)_ Disable email notifications. Use `emails_enabled` instead. |
| `emails_enabled` | boolean | no | Enable email notifications. |
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
@@ -1001,6 +1003,7 @@ PUT /groups/:id
| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). |
| `default_branch_protection_defaults` | hash | no | See [Options for `default_branch_protection_defaults`](#options-for-default_branch_protection_defaults). |
| `description` | string | no | The description of the group. |
+| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `all` to allow both protocols. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/436618) in GitLab 16.9. |
| `emails_disabled` | boolean | no | _([Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127899) in GitLab 16.5.)_ Disable email notifications. Use `emails_enabled` instead. |
| `emails_enabled` | boolean | no | Enable email notifications. |
| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
@@ -1060,6 +1063,7 @@ Example response:
"full_path": "h5bp",
"file_template_project_id": 1,
"parent_id": null,
+ "enabled_git_access_protocol": "all",
"created_at": "2020-01-15T12:36:29.590Z",
"prevent_sharing_groups_outside_hierarchy": false,
"projects": [ // Deprecated and will be removed in API v5
diff --git a/doc/api/usage_data.md b/doc/api/usage_data.md
index 41a9901665d..b0e7a1d2998 100644
--- a/doc/api/usage_data.md
+++ b/doc/api/usage_data.md
@@ -8,6 +8,38 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The Service Data API is associated with [Service Ping](../development/internal_analytics/service_ping/index.md).
+## Export Service Ping data
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141446) in GitLab 16.9.
+
+Requires a Personal Access Token with `read_service_ping` scope.
+
+Returns the JSON payload collected in Service Ping. If no payload data is available in the application cache, it returns empty response.
+If payload data is empty, make sure the [Service Ping feature is enabled](../administration/settings/usage_statistics.md#enable-or-disable-service-ping) and
+wait for the cron job to be executed, or [generate payload data manually](../development/internal_analytics/service_ping/troubleshooting.md#generate-service-ping).
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/usage_data/service_ping"
+```
+
+Example response:
+
+```json
+ "recorded_at": "2024-01-15T23:33:50.387Z",
+ "license": {},
+ "counts": {
+ "assignee_lists": 0,
+ "ci_builds": 463,
+ "ci_external_pipelines": 0,
+ "ci_pipeline_config_auto_devops": 0,
+ "ci_pipeline_config_repository": 0,
+ "ci_triggers": 0,
+ "ci_pipeline_schedules": 0
+...
+```
+
## Export metric definitions as a single YAML file
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57270) in GitLab 13.11.
diff --git a/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb b/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb
index ee4be97dc6d..6a1f1f0f5e3 100644
--- a/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb
+++ b/gems/gitlab-http/lib/gitlab/http_v2/new_connection_adapter.rb
@@ -62,7 +62,7 @@ module Gitlab
def validate_url_with_proxy!(url)
UrlBlocker.validate_url_with_proxy!(url, **url_blocker_options)
rescue UrlBlocker::BlockedUrlError => e
- raise HTTP_V2::BlockedUrlError, "URL is blocked: #{e.message}"
+ raise BlockedUrlError, "URL is blocked: #{e.message}"
end
def url_blocker_options
diff --git a/lib/api/entities/group_detail.rb b/lib/api/entities/group_detail.rb
index f3d64315203..9f3ced7d717 100644
--- a/lib/api/entities/group_detail.rb
+++ b/lib/api/entities/group_detail.rb
@@ -7,6 +7,7 @@ module API
SharedGroupWithGroup.represent(group.shared_with_group_links_visible_to_user(options[:current_user]))
end
expose :runners_token, if: ->(_, options) { options[:user_can_admin_group] }
+ expose :enabled_git_access_protocol, if: ->(group, options) { group.root? && options[:user_can_admin_group] }
expose :prevent_sharing_groups_outside_hierarchy,
if: ->(group) { group.root? && group.namespace_settings.present? }
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index fbe13bfe8f7..1861ef7c402 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -35,6 +35,7 @@ module API
optional :developer_can_initial_push, type: Boolean, desc: 'Allow developers to initial push'
end
optional :shared_runners_setting, type: String, values: ::Namespace::SHARED_RUNNERS_SETTINGS, desc: 'Enable/disable shared runners for the group and its subgroups and projects'
+ optional :enabled_git_access_protocol, type: String, values: %w[ssh http all], desc: 'Allow only the selected protocols to be used for Git access.'
end
params :optional_params_ee do
diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb
index 0d1c6cb2281..67bf2725988 100644
--- a/lib/api/usage_data.rb
+++ b/lib/api/usage_data.rb
@@ -2,6 +2,8 @@
module API
class UsageData < ::API::Base
+ include APIGuard
+
before { authenticate_non_get! }
feature_category :service_ping
@@ -12,6 +14,33 @@ module API
forbidden!('Invalid CSRF token is provided') unless verified_request?
end
+ resource :service_ping do
+ allow_access_with_scope :read_service_ping
+
+ before do
+ authenticated_as_admin!
+ end
+
+ desc 'Get the latest ServicePing payload' do
+ detail 'Introduces in Gitlab 16.9. Requires Personal Access Token with read_service_ping scope.'
+ success code: 200
+ failure [
+ { code: 401, message: '401 Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[usage_data]
+ produces ['application/json']
+ end
+
+ get do
+ content_type 'application/json'
+
+ Rails.cache.fetch(Gitlab::Usage::ServicePingReport::CACHE_KEY) ||
+ ::RawUsageData.for_current_reporting_cycle.first&.payload || {}
+ end
+ end
+
desc 'Track usage data event' do
detail 'This feature was introduced in GitLab 13.4.'
success code: 200
diff --git a/lib/gitlab/click_house.rb b/lib/gitlab/click_house.rb
new file mode 100644
index 00000000000..81468ab2875
--- /dev/null
+++ b/lib/gitlab/click_house.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ClickHouse
+ DATABASES = [:main].freeze
+
+ def self.configured?
+ DATABASES.all? { |db| ::ClickHouse::Client.database_configured?(db) }
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 6dee9a404f4..3ee46019a06 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -491,6 +491,8 @@ module Gitlab
private_class_method :increment_call_count
def self.decrement_call_count(key)
+ return unless Gitlab::SafeRequestStore[key]
+
Gitlab::SafeRequestStore[key] -= 1
end
private_class_method :decrement_call_count
diff --git a/lib/gitlab/http.rb b/lib/gitlab/http.rb
index 958b415e18f..593ea4f721e 100644
--- a/lib/gitlab/http.rb
+++ b/lib/gitlab/http.rb
@@ -6,8 +6,6 @@
# the usages to the new gem.
#
-require_relative 'http_connection_adapter'
-
module Gitlab
class HTTP
BlockedUrlError = Gitlab::HTTP_V2::BlockedUrlError
diff --git a/lib/gitlab/http_connection_adapter.rb b/lib/gitlab/http_connection_adapter.rb
deleted file mode 100644
index 8e9a63a9f7f..00000000000
--- a/lib/gitlab/http_connection_adapter.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-# This class is part of the Gitlab::HTTP wrapper. It handles local requests and header timeouts
-#
-# 1. Local requests
-# Depending on the value of the global setting allow_local_requests_from_web_hooks_and_services,
-# this adapter will allow/block connection to internal IPs and/or urls.
-#
-# This functionality can be overridden by providing the setting the option
-# allow_local_requests = true in the request. For example:
-# Gitlab::HTTP.get('http://www.gitlab.com', allow_local_requests: true)
-#
-# This option will take precedence over the global setting.
-#
-# 2. Header timeouts
-# When the use_read_total_timeout option is used, that means the receiver
-# of the HTTP request cannot be trusted. Gitlab::BufferedIo will be used,
-# to read header data. It is a modified version of Net::BufferedIO that
-# raises a timeout error if reading header data takes too much time.
-
-require_relative 'utils/override'
-
-module Gitlab
- class HTTPConnectionAdapter < HTTParty::ConnectionAdapter
- extend ::Gitlab::Utils::Override
-
- override :connection
- def connection
- result = validate_url_with_proxy!(uri)
- @uri = result.uri
- hostname = result.hostname
-
- http = super
- http.hostname_override = hostname if hostname
-
- unless result.use_proxy
- http.proxy_from_env = false
- http.proxy_address = nil
- end
-
- gitlab_http = Gitlab::NetHttpAdapter.new(http.address, http.port)
-
- http.instance_variables.each do |variable|
- gitlab_http.instance_variable_set(variable, http.instance_variable_get(variable))
- end
-
- gitlab_http
- end
-
- private
-
- def validate_url_with_proxy!(url)
- Gitlab::UrlBlocker.validate_url_with_proxy!(
- url, allow_local_network: allow_local_requests?,
- allow_localhost: allow_local_requests?,
- allow_object_storage: allow_object_storage?,
- dns_rebind_protection: dns_rebind_protection?,
- schemes: %w[http https])
- rescue Gitlab::HTTP_V2::UrlBlocker::BlockedUrlError => e
- raise Gitlab::HTTP::BlockedUrlError, "URL is blocked: #{e.message}"
- end
-
- def allow_local_requests?
- options.fetch(:allow_local_requests, allow_settings_local_requests?)
- end
-
- def allow_object_storage?
- options.fetch(:allow_object_storage, false)
- end
-
- def dns_rebind_protection?
- Gitlab::CurrentSettings.dns_rebinding_protection_enabled?
- end
-
- def allow_settings_local_requests?
- Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
- end
- end
-end
diff --git a/lib/gitlab/import_export/remote_stream_upload.rb b/lib/gitlab/import_export/remote_stream_upload.rb
index 1fb3faf0767..8f761cf37bb 100644
--- a/lib/gitlab/import_export/remote_stream_upload.rb
+++ b/lib/gitlab/import_export/remote_stream_upload.rb
@@ -77,7 +77,10 @@ module Gitlab
attr_reader :download_url, :upload_url, :upload_method, :upload_content_type, :logger
def receive_data(uri)
- http = Gitlab::HTTPConnectionAdapter.new(URI(uri), {}).connection
+ http = Gitlab::HTTP_V2::NewConnectionAdapter.new(URI(uri), {
+ allow_local_requests: Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?,
+ dns_rebind_protection: Gitlab::CurrentSettings.dns_rebinding_protection_enabled?
+ }).connection
http.start do
request = Net::HTTP::Get.new(uri)
@@ -95,7 +98,10 @@ module Gitlab
end
def send_data(uri, content_length, chunks)
- http = Gitlab::HTTPConnectionAdapter.new(URI(uri), {}).connection
+ http = Gitlab::HTTP_V2::NewConnectionAdapter.new(URI(uri), {
+ allow_local_requests: Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?,
+ dns_rebind_protection: Gitlab::CurrentSettings.dns_rebinding_protection_enabled?
+ }).connection
http.start do
request = upload_request_class(upload_method).new(uri)
diff --git a/lib/gitlab/metrics/global_search_slis.rb b/lib/gitlab/metrics/global_search_slis.rb
index 530bebd72ab..1da0ad6797b 100644
--- a/lib/gitlab/metrics/global_search_slis.rb
+++ b/lib/gitlab/metrics/global_search_slis.rb
@@ -8,6 +8,7 @@ module Gitlab
# gathered on 25-10-2022
# from https://log.gprd.gitlab.net/goto/0c89cd80-23af-11ed-8656-f5f2137823ba (internal only)
BASIC_CONTENT_TARGET_S = 8.812
+ BASIC_MR_TARGET_S = 15
BASIC_CODE_TARGET_S = 27.538
ADVANCED_CONTENT_TARGET_S = 2.452
ADVANCED_CODE_TARGET_S = 15.52
@@ -35,7 +36,9 @@ module Gitlab
private
def duration_target(search_type, search_scope)
- if search_type == 'basic' && content_search?(search_scope)
+ if search_type == 'basic' && search_scope == 'merge_requests'
+ BASIC_MR_TARGET_S
+ elsif search_type == 'basic' && content_search?(search_scope)
BASIC_CONTENT_TARGET_S
elsif search_type == 'basic' && code_search?(search_scope)
BASIC_CODE_TARGET_S
diff --git a/lib/gitlab/sidekiq_middleware/pause_control/strategies/click_house_migration.rb b/lib/gitlab/sidekiq_middleware/pause_control/strategies/click_house_migration.rb
index adeb0524567..c1d33885a40 100644
--- a/lib/gitlab/sidekiq_middleware/pause_control/strategies/click_house_migration.rb
+++ b/lib/gitlab/sidekiq_middleware/pause_control/strategies/click_house_migration.rb
@@ -9,7 +9,7 @@ module Gitlab
def should_pause?
return false unless Feature.enabled?(:pause_clickhouse_workers_during_migration)
- ClickHouse::MigrationSupport::ExclusiveLock.pause_workers?
+ ::ClickHouse::MigrationSupport::ExclusiveLock.pause_workers?
end
end
end
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index b8a6e701876..16b0f5bedba 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -101,6 +101,8 @@ namespace :gitlab do
# gettext:compile needs to run before rake:assets:precompile because
# app/assets/javascripts/locale/**/app.js are pre-compiled by Sprockets
Gitlab::TaskHelpers.invoke_and_time_task('gettext:compile')
+ # Skip Yarn Install when using Cssbundling
+ Rake::Task["css:install"].clear if defined?(Cssbundling)
Gitlab::TaskHelpers.invoke_and_time_task('rake:assets:precompile')
log_path = ENV['WEBPACK_COMPILE_LOG_PATH']
diff --git a/scripts/frontend/clean_css_assets.mjs b/scripts/frontend/clean_css_assets.mjs
new file mode 100755
index 00000000000..de89b9820f7
--- /dev/null
+++ b/scripts/frontend/clean_css_assets.mjs
@@ -0,0 +1,72 @@
+#!/usr/bin/env node
+
+import { argv, cwd } from 'node:process';
+import { join, resolve, relative, dirname } from 'node:path';
+import { mkdir, stat, readFile, writeFile } from 'node:fs/promises';
+import glob from 'glob';
+import * as esbuild from 'esbuild';
+import prettier from 'prettier';
+
+/**
+ * VISION: This script could be made more generalizable, to be able to
+ * "normalize" our complete asset folder in order to easily diff them.
+ *
+ * It might even be great to have support for using MRs/Pipelines, etc.
+ *
+ * normalize_assets.mjs https://gitlab.com/gitlab-org/gitlab/-/pipelines/1143467234 tmp/current_master
+ * normalize_assets.mjs https://gitlab.com/gitlab-org/gitlab/-/merge_requests/140611 tmp/after_change
+ */
+
+/**
+ * 1. this function removes the `hash` from the file name
+ * (sprockets is unhappy compiling without hash)
+ * 2. Minifies the css, to remove comments and normalize things like
+ * `#ffffff` and `#fff` or `.5rem` and `0.5rem`
+ * 3. Prettifies it again, to make it diffable
+ */
+async function cleanUpCSSFile(sourceFile, sourceDir, targetDir) {
+ const targetFile = join(targetDir, relative(sourceDir, sourceFile)).replace(
+ /-[a-f0-9]{20,}.css$/,
+ '.css',
+ );
+ await mkdir(dirname(targetFile), { recursive: true });
+
+ const content = await readFile(sourceFile, 'utf-8');
+ const minified = await esbuild.transform(content, {
+ minify: true,
+ loader: 'css',
+ });
+ const pretty = await prettier.format(minified.code, { parser: 'css' });
+ console.log(`Copied ${relative(cwd(), sourceFile)} to \n\t${relative(cwd(), targetFile)}`);
+ return writeFile(targetFile, pretty, 'utf-8');
+}
+
+async function main() {
+ const [, , sourceDirRel, targetDirRel] = argv;
+
+ if (!sourceDirRel || !targetDirRel) {
+ throw new Error('Please start this script like with two parameters: <sourcePath> <targetPath>');
+ }
+
+ const sourceDir = resolve(cwd(), sourceDirRel);
+
+ const s = await stat(sourceDir);
+ if (!s.isDirectory()) {
+ throw new Error(`sourcePath ${sourceDir} is not a directory`);
+ }
+
+ const targetDir = resolve(cwd(), targetDirRel);
+
+ const cssFiles = glob.sync(join(sourceDir, '**/*.css'));
+
+ return Promise.all(
+ cssFiles.map((sourceFile) => cleanUpCSSFile(sourceFile, sourceDir, targetDir)),
+ );
+}
+
+try {
+ await main();
+} catch (e) {
+ console.error(e);
+ process.exitCode = 1;
+}
diff --git a/scripts/frontend/compare_css_compilers.sh b/scripts/frontend/compare_css_compilers.sh
new file mode 100755
index 00000000000..faf20871678
--- /dev/null
+++ b/scripts/frontend/compare_css_compilers.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
+
+if [ ! -d "glfm_specification" ] || [ ! -f "GITALY_SERVER_VERSION" ]; then
+ echo 'Please run this from the gitlab root folder with `./scripts/frontend/compare_css_compilers.sh`'
+ exit 1
+fi
+
+function clean_up {
+ rm -rf public/assets
+ rm -rf app/assets/builds/*
+ rm -rf tmp/cache/assets
+}
+
+rm -rf tmp/css_compare
+clean_up
+
+export SKIP_YARN_INSTALL=1
+
+echo "Compiling with sassc-rails"
+export USE_NEW_CSS_PIPELINE=0
+time bin/rails assets:precompile
+scripts/frontend/clean_css_assets.mjs public/assets tmp/css_compare/sassc-rails
+
+clean_up
+
+export USE_NEW_CSS_PIPELINE=1
+echo "Compiling with dart-sass"
+time bin/rails assets:precompile
+scripts/frontend/clean_css_assets.mjs public/assets tmp/css_compare/cssbundling
+
+clean_up
+
+echo 'You now can run `diff -u tmp/css_compare/sassc-rails tmp/css_compare/cssbundling` to diff the two'
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index 190c00092b6..3061697551e 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SentNotificationsController do
+RSpec.describe SentNotificationsController, feature_category: :shared do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:private_project) { create(:project, :private) }
@@ -235,7 +235,9 @@ RSpec.describe SentNotificationsController do
end
end
- let(:sent_notification) { create(:sent_notification, project: project, noteable: merge_request, recipient: user) }
+ let(:sent_notification) do
+ create(:sent_notification, project: project, noteable: merge_request, recipient: user)
+ end
before do
unsubscribe
@@ -299,12 +301,36 @@ RSpec.describe SentNotificationsController do
end
context 'when support bot is the notification recipient' do
- let(:sent_notification) { create(:sent_notification, project: target_project, noteable: noteable, recipient: Users::Internal.support_bot) }
+ let(:sent_notification) do
+ create(:sent_notification,
+ project: target_project, noteable: noteable, recipient: Users::Internal.support_bot)
+ end
it 'deletes the external author on the issue' do
expect { unsubscribe }.to change { issue.issue_email_participants.count }.by(-1)
end
+ context 'when sent_notification contains issue_email_participant' do
+ let!(:other_issue_email_participant) do
+ create(:issue_email_participant, issue: issue, email: 'other@example.com')
+ end
+
+ let(:sent_notification) do
+ create(:sent_notification,
+ project: target_project,
+ noteable: noteable,
+ recipient: Users::Internal.support_bot,
+ issue_email_participant: other_issue_email_participant
+ )
+ end
+
+ it 'deletes the connected issue email participant' do
+ expect { unsubscribe }.to change { issue.issue_email_participants.count }.by(-1)
+ # Ensure external author is still present
+ expect(issue.email_participants_emails).to contain_exactly(email)
+ end
+ end
+
context 'when noteable is not an issue' do
let(:noteable) { merge_request }
diff --git a/spec/frontend/content_editor/extensions/attachment_spec.js b/spec/frontend/content_editor/extensions/attachment_spec.js
index f037ac520fe..18ce6c9ab59 100644
--- a/spec/frontend/content_editor/extensions/attachment_spec.js
+++ b/spec/frontend/content_editor/extensions/attachment_spec.js
@@ -126,12 +126,12 @@ describe('content_editor/extensions/attachment', () => {
describe.each`
nodeType | html | file | mediaType
- ${'image (png)'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${imageFile} | ${(attrs) => image(attrs)}
- ${'image (svg)'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_SVG_HTML} | ${imageFileSvg} | ${(attrs) => image(attrs)}
+ ${'image'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_HTML} | ${imageFile} | ${(attrs) => image(attrs)}
+ ${'image'} | ${PROJECT_WIKI_ATTACHMENT_IMAGE_SVG_HTML} | ${imageFileSvg} | ${(attrs) => image(attrs)}
${'audio'} | ${PROJECT_WIKI_ATTACHMENT_AUDIO_HTML} | ${audioFile} | ${(attrs) => audio(attrs)}
${'video'} | ${PROJECT_WIKI_ATTACHMENT_VIDEO_HTML} | ${videoFile} | ${(attrs) => video(attrs)}
${'drawioDiagram'} | ${PROJECT_WIKI_ATTACHMENT_DRAWIO_DIAGRAM_HTML} | ${drawioDiagramFile} | ${(attrs) => drawioDiagram(attrs)}
- `('when the file is $nodeType', ({ html, file, mediaType }) => {
+ `('when the file is $nodeType', ({ nodeType, html, file, mediaType }) => {
beforeEach(() => {
renderMarkdown.mockResolvedValue(html);
});
@@ -149,7 +149,13 @@ describe('content_editor/extensions/attachment', () => {
it('inserts a media content with src set to the encoded content and uploading=file_name', async () => {
const expectedDoc = doc(
- p(mediaType({ uploading: file.name, src: blobUrl, alt: file.name })),
+ p(
+ mediaType({
+ uploading: expect.stringMatching(new RegExp(`${nodeType}[0-9]+`)),
+ src: blobUrl,
+ alt: file.name,
+ }),
+ ),
);
await expectDocumentAfterTransaction({
@@ -248,7 +254,12 @@ describe('content_editor/extensions/attachment', () => {
it('inserts a link with a blob url', async () => {
const expectedDoc = doc(
- p(link({ uploading: attachmentFile.name, href: blobUrl }, 'test-file.zip')),
+ p(
+ link(
+ { uploading: expect.stringMatching(/file[0-9]+/), href: blobUrl },
+ 'test-file.zip',
+ ),
+ ),
);
await expectDocumentAfterTransaction({
@@ -334,68 +345,228 @@ describe('content_editor/extensions/attachment', () => {
};
it.each([
- [1, () => doc(p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')))],
+ [
+ 1,
+ () =>
+ doc(
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ ),
+ ],
[
2,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
),
],
[
3,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
),
],
[
4,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
),
],
[
5,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
),
],
[
6,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
),
],
[
7,
() =>
doc(
- p(link({ href: blobUrl, uploading: 'test-file.zip' }, 'test-file.zip')),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file.zip',
+ ),
+ ),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -412,12 +583,46 @@ describe('content_editor/extensions/attachment', () => {
'test-file.zip',
),
),
- p(image({ alt: 'test-file.png', src: blobUrl, uploading: 'test-file.png' })),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ image({
+ alt: 'test-file.png',
+ src: blobUrl,
+ uploading: expect.stringMatching(/image[0-9]+/),
+ }),
+ ),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -442,11 +647,39 @@ describe('content_editor/extensions/attachment', () => {
uploading: false,
}),
),
- p(video({ alt: 'test-file.mp4', src: blobUrl, uploading: 'test-file.mp4' })),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ video({
+ alt: 'test-file.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -479,10 +712,32 @@ describe('content_editor/extensions/attachment', () => {
uploading: false,
}),
),
- p(link({ href: blobUrl, uploading: 'test-file1.zip' }, 'test-file1.zip')),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file1.zip',
+ ),
+ ),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -525,9 +780,26 @@ describe('content_editor/extensions/attachment', () => {
'test-file1.zip',
),
),
- p(link({ href: blobUrl, uploading: 'test-file2.zip' }, 'test-file2.zip')),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ link(
+ { href: blobUrl, uploading: expect.stringMatching(/file[0-9]+/) },
+ 'test-file2.zip',
+ ),
+ ),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -580,8 +852,20 @@ describe('content_editor/extensions/attachment', () => {
'test-file2.zip',
),
),
- p(video({ alt: 'test-file1.mp4', src: blobUrl, uploading: 'test-file1.mp4' })),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ video({
+ alt: 'test-file1.mp4',
+ src: blobUrl,
+ uploading: expect.stringMatching(/video[0-9]+/),
+ }),
+ ),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
@@ -642,7 +926,13 @@ describe('content_editor/extensions/attachment', () => {
uploading: false,
}),
),
- p(audio({ alt: 'test-file.mp3', src: blobUrl, uploading: 'test-file.mp3' })),
+ p(
+ audio({
+ alt: 'test-file.mp3',
+ src: blobUrl,
+ uploading: expect.stringMatching(/audio[0-9]+/),
+ }),
+ ),
),
],
[
diff --git a/spec/graphql/mutations/work_items/update_task_spec.rb b/spec/graphql/mutations/work_items/update_task_spec.rb
deleted file mode 100644
index cb37a72bbdd..00000000000
--- a/spec/graphql/mutations/work_items/update_task_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Mutations::WorkItems::UpdateTask do
- let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
- let_it_be(:referenced_work_item, refind: true) { create(:work_item, project: project, title: 'REFERENCED') }
- let_it_be(:parent_work_item) do
- create(:work_item, project: project, description: "- [ ] #{referenced_work_item.to_reference}+")
- end
-
- let(:task_params) { { title: 'UPDATED' } }
- let(:task_input) { { id: referenced_work_item.to_global_id }.merge(task_params) }
- let(:input) { { id: parent_work_item.to_global_id, task_data: task_input } }
- let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
-
- describe '#resolve' do
- subject(:resolve) do
- mutation.resolve(**input)
- end
-
- context 'when user has sufficient permissions' do
- let(:current_user) { developer }
-
- it 'expires etag cache for parent work item' do
- allow(WorkItem).to receive(:find).and_call_original
- allow(WorkItem).to receive(:find).with(parent_work_item.id.to_s).and_return(parent_work_item)
-
- expect(parent_work_item).to receive(:expire_etag_cache)
-
- resolve
- end
- end
- end
-end
diff --git a/spec/lib/api/entities/group_detail_spec.rb b/spec/lib/api/entities/group_detail_spec.rb
index 8fcb120c809..f3200b28c4d 100644
--- a/spec/lib/api/entities/group_detail_spec.rb
+++ b/spec/lib/api/entities/group_detail_spec.rb
@@ -2,18 +2,50 @@
require 'spec_helper'
-RSpec.describe API::Entities::GroupDetail do
+RSpec.describe API::Entities::GroupDetail, feature_category: :groups_and_projects do
describe '#as_json' do
- it 'includes prevent_sharing_groups_outside_hierarchy for a root group' do
- group = create(:group)
+ subject { described_class.new(group, options).as_json }
- expect(described_class.new(group).as_json).to include(prevent_sharing_groups_outside_hierarchy: false)
+ let_it_be(:root_group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, :nested) }
+
+ let(:options) { {} }
+
+ describe '#prevent_sharing_groups_outside_hierarchy' do
+ context 'for a root group' do
+ let(:group) { root_group }
+
+ it { is_expected.to include(:prevent_sharing_groups_outside_hierarchy) }
+ end
+
+ context 'for a subgroup' do
+ let(:group) { subgroup }
+
+ it { is_expected.not_to include(:prevent_sharing_groups_outside_hierarchy) }
+ end
end
- it 'excludes prevent_sharing_groups_outside_hierarchy for a subgroup' do
- subgroup = build(:group, :nested)
+ describe '#enabled_git_access_protocol' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:group, :can_admin_group, :includes_field) do
+ ref(:root_group) | false | false
+ ref(:root_group) | true | true
+ ref(:subgroup) | false | false
+ ref(:subgroup) | true | false
+ end
+
+ with_them do
+ let(:options) { { user_can_admin_group: can_admin_group } }
- expect(described_class.new(subgroup).as_json.keys).not_to include(:prevent_sharing_groups_outside_hierarchy)
+ it 'verifies presence of the field' do
+ if includes_field
+ is_expected.to include(:enabled_git_access_protocol)
+ else
+ is_expected.not_to include(:enabled_git_access_protocol)
+ end
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/click_house_spec.rb b/spec/lib/gitlab/click_house_spec.rb
new file mode 100644
index 00000000000..3241eca34ae
--- /dev/null
+++ b/spec/lib/gitlab/click_house_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ClickHouse, feature_category: :database do
+ context 'when ClickHouse is not configured' do
+ it 'returns false' do
+ expect(described_class).not_to be_configured
+ end
+ end
+
+ context 'when ClickHouse is configured', :click_house do
+ it 'returns false' do
+ expect(described_class).to be_configured
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 796fe75521a..5ff3bc20bc1 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -365,6 +365,20 @@ RSpec.describe Gitlab::GitalyClient, feature_category: :gitaly do
it 'returns the result of the allow_n_plus_1_calls block' do
expect(described_class.allow_n_plus_1_calls { "result" }).to eq("result")
end
+
+ context 'when the `gitaly_call_count_exception_block_depth` key is not present' do
+ before do
+ allow(Gitlab::SafeRequestStore).to receive(:[]).with(:gitaly_call_count_exception_block_depth).and_return(0, 1, nil)
+ allow(Gitlab::SafeRequestStore).to receive(:+)
+ allow(Gitlab::SafeRequestStore).to receive(:-)
+ end
+
+ it 'does not decrement call count' do
+ expect(Gitlab::SafeRequestStore).not_to have_received(:-)
+
+ described_class.allow_n_plus_1_calls { "result" }
+ end
+ end
end
context 'when RequestStore is not active' do
diff --git a/spec/lib/gitlab/http_connection_adapter_spec.rb b/spec/lib/gitlab/http_connection_adapter_spec.rb
deleted file mode 100644
index fac0c1a2a9f..00000000000
--- a/spec/lib/gitlab/http_connection_adapter_spec.rb
+++ /dev/null
@@ -1,161 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::HTTPConnectionAdapter, feature_category: :shared do
- include StubRequests
-
- let(:uri) { URI('https://example.org') }
- let(:options) { {} }
-
- subject(:connection) { described_class.new(uri, options).connection }
-
- describe '#connection' do
- before do
- stub_all_dns('https://example.org', ip_address: '93.184.216.34')
- end
-
- context 'when local requests are allowed' do
- let(:options) { { allow_local_requests: true } }
-
- it 'sets up the connection' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('93.184.216.34')
- expect(connection.hostname_override).to eq('example.org')
- expect(connection.addr_port).to eq('example.org')
- expect(connection.port).to eq(443)
- end
- end
-
- context 'when local requests are not allowed' do
- let(:options) { { allow_local_requests: false } }
-
- it 'sets up the connection' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('93.184.216.34')
- expect(connection.hostname_override).to eq('example.org')
- expect(connection.addr_port).to eq('example.org')
- expect(connection.port).to eq(443)
- end
-
- context 'when it is a request to local network' do
- let(:uri) { URI('http://172.16.0.0/12') }
-
- it 'raises error' do
- expect { subject }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
- "URL is blocked: Requests to the local network are not allowed"
- )
- end
-
- context 'when local request allowed' do
- let(:options) { { allow_local_requests: true } }
-
- it 'sets up the connection' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('172.16.0.0')
- expect(connection.hostname_override).to be(nil)
- expect(connection.addr_port).to eq('172.16.0.0')
- expect(connection.port).to eq(80)
- end
- end
- end
-
- context 'when it is a request to local address' do
- let(:uri) { URI('http://127.0.0.1') }
-
- it 'raises error' do
- expect { subject }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
- "URL is blocked: Requests to localhost are not allowed"
- )
- end
-
- context 'when local request allowed' do
- let(:options) { { allow_local_requests: true } }
-
- it 'sets up the connection' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('127.0.0.1')
- expect(connection.hostname_override).to be(nil)
- expect(connection.addr_port).to eq('127.0.0.1')
- expect(connection.port).to eq(80)
- end
- end
- end
-
- context 'when port different from URL scheme is used' do
- let(:uri) { URI('https://example.org:8080') }
-
- it 'sets up the addr_port accordingly' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('93.184.216.34')
- expect(connection.hostname_override).to eq('example.org')
- expect(connection.addr_port).to eq('example.org:8080')
- expect(connection.port).to eq(8080)
- end
- end
- end
-
- context 'when DNS rebinding protection is disabled' do
- before do
- stub_application_setting(dns_rebinding_protection_enabled: false)
- end
-
- it 'sets up the connection' do
- expect(connection).to be_a(Gitlab::NetHttpAdapter)
- expect(connection.address).to eq('example.org')
- expect(connection.hostname_override).to eq(nil)
- expect(connection.addr_port).to eq('example.org')
- expect(connection.port).to eq(443)
- end
- end
-
- context 'when proxy is enabled' do
- before do
- stub_env('http_proxy', 'http://proxy.example.com')
- end
-
- it 'proxy stays configured' do
- expect(connection.proxy?).to be true
- expect(connection.proxy_from_env?).to be true
- expect(connection.proxy_address).to eq('proxy.example.com')
- end
-
- context 'when no_proxy matches the request' do
- before do
- stub_env('no_proxy', 'example.org')
- end
-
- it 'proxy is disabled' do
- expect(connection.proxy?).to be false
- expect(connection.proxy_from_env?).to be false
- expect(connection.proxy_address).to be nil
- end
- end
-
- context 'when no_proxy does not match the request' do
- before do
- stub_env('no_proxy', 'example.com')
- end
-
- it 'proxy stays configured' do
- expect(connection.proxy?).to be true
- expect(connection.proxy_from_env?).to be true
- expect(connection.proxy_address).to eq('proxy.example.com')
- end
- end
- end
-
- context 'when URL scheme is not HTTP/HTTPS' do
- let(:uri) { URI('ssh://example.org') }
-
- it 'raises error' do
- expect { subject }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
- "URL is blocked: Only allowed schemes are http, https"
- )
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 6d5c17176dc..9e83b7d85e9 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -1010,6 +1010,7 @@ epic:
- user_note_authors
- boards_epic_user_preferences
- epic_board_positions
+- work_item
epic_issue:
- epic
- issue
diff --git a/spec/lib/gitlab/import_export/remote_stream_upload_spec.rb b/spec/lib/gitlab/import_export/remote_stream_upload_spec.rb
index 3d9d6e1b96b..c27bc7b5fe1 100644
--- a/spec/lib/gitlab/import_export/remote_stream_upload_spec.rb
+++ b/spec/lib/gitlab/import_export/remote_stream_upload_spec.rb
@@ -23,10 +23,14 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
describe '#execute' do
context 'when download request and upload request return 200' do
- it 'uploads the downloaded content' do
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
+ stub_application_setting(dns_rebinding_protection_enabled: false)
stub_request(:get, download_url).to_return(status: 200, body: 'ABC', headers: { 'Content-Length' => 3 })
stub_request(:post, upload_url)
+ end
+ it 'uploads the downloaded content' do
subject.execute
expect(
@@ -35,6 +39,16 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
)
).to have_been_made
end
+
+ it 'calls the connection adapter twice with required args' do
+ expect(Gitlab::HTTP_V2::NewConnectionAdapter)
+ .to receive(:new).twice.with(instance_of(URI::HTTP), {
+ allow_local_requests: true,
+ dns_rebind_protection: false
+ }).and_call_original
+
+ subject.execute
+ end
end
context 'when upload method is put' do
@@ -87,7 +101,7 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
it 'raises error' do
expect { subject.execute }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
+ Gitlab::HTTP_V2::BlockedUrlError,
"URL is blocked: Requests to localhost are not allowed"
)
end
@@ -113,7 +127,7 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
it 'raises error' do
expect { subject.execute }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
+ Gitlab::HTTP_V2::BlockedUrlError,
"URL is blocked: Requests to the local network are not allowed"
)
end
@@ -141,7 +155,7 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
stub_request(:get, download_url)
expect { subject.execute }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
+ Gitlab::HTTP_V2::BlockedUrlError,
"URL is blocked: Requests to localhost are not allowed"
)
end
@@ -167,7 +181,7 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
it 'raises error' do
expect { subject.execute }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
+ Gitlab::HTTP_V2::BlockedUrlError,
"URL is blocked: Requests to the local network are not allowed"
)
end
@@ -191,7 +205,7 @@ RSpec.describe Gitlab::ImportExport::RemoteStreamUpload do
stub_full_request(upload_url, ip_address: '127.0.0.1', method: upload_method)
expect { subject.execute }.to raise_error(
- Gitlab::HTTP::BlockedUrlError,
+ Gitlab::HTTP_V2::BlockedUrlError,
"URL is blocked: Requests to localhost are not allowed"
)
end
diff --git a/spec/lib/gitlab/metrics/global_search_slis_spec.rb b/spec/lib/gitlab/metrics/global_search_slis_spec.rb
index 68793db6e41..9aa4f3b106e 100644
--- a/spec/lib/gitlab/metrics/global_search_slis_spec.rb
+++ b/spec/lib/gitlab/metrics/global_search_slis_spec.rb
@@ -87,6 +87,10 @@ RSpec.describe Gitlab::Metrics::GlobalSearchSlis, feature_category: :global_sear
end
describe '#record_apdex' do
+ before do
+ allow(::Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return('end')
+ end
+
where(:search_type, :code_search, :duration_target) do
'basic' | false | 8.812
'basic' | true | 27.538
@@ -96,10 +100,6 @@ RSpec.describe Gitlab::Metrics::GlobalSearchSlis, feature_category: :global_sear
end
with_them do
- before do
- allow(::Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return('end')
- end
-
let(:search_scope) { code_search ? 'blobs' : 'issues' }
it 'increments the global_search SLI as a success if the elapsed time is within the target' do
@@ -144,6 +144,46 @@ RSpec.describe Gitlab::Metrics::GlobalSearchSlis, feature_category: :global_sear
)
end
end
+
+ context 'when the search scope is merge_requests and the search type is basic' do
+ it 'increments the global_search SLI as a success if the elapsed time is within the target' do
+ expect(Gitlab::Metrics::Sli::Apdex[:global_search]).to receive(:increment).with(
+ labels: {
+ search_type: 'basic',
+ search_level: 'global',
+ search_scope: 'merge_requests',
+ endpoint_id: 'end'
+ },
+ success: true
+ )
+
+ described_class.record_apdex(
+ elapsed: 14,
+ search_type: 'basic',
+ search_level: 'global',
+ search_scope: 'merge_requests'
+ )
+ end
+
+ it 'increments the global_search SLI as a failure if the elapsed time is not within the target' do
+ expect(Gitlab::Metrics::Sli::Apdex[:global_search]).to receive(:increment).with(
+ labels: {
+ search_type: 'basic',
+ search_level: 'global',
+ search_scope: 'merge_requests',
+ endpoint_id: 'end'
+ },
+ success: false
+ )
+
+ described_class.record_apdex(
+ elapsed: 16,
+ search_type: 'basic',
+ search_level: 'global',
+ search_scope: 'merge_requests'
+ )
+ end
+ end
end
describe '#record_error_rate' do
diff --git a/spec/mailers/emails/service_desk_spec.rb b/spec/mailers/emails/service_desk_spec.rb
index 3ed531a16bc..6653a599602 100644
--- a/spec/mailers/emails/service_desk_spec.rb
+++ b/spec/mailers/emails/service_desk_spec.rb
@@ -19,13 +19,10 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let_it_be(:credential) { create(:service_desk_custom_email_credential, project: project) }
let_it_be(:verification) { create(:service_desk_custom_email_verification, project: project) }
let_it_be(:service_desk_setting) { create(:service_desk_setting, project: project, custom_email: 'user@example.com') }
+ let_it_be(:issue_email_participant) { create(:issue_email_participant, issue: issue, email: email) }
let(:template) { double(content: template_content) }
- before_all do
- issue.issue_email_participants.create!(email: email)
- end
-
before do
# Because we use global project and custom email instances, make sure
# custom email is disabled in all regular cases to avoid flakiness.
@@ -50,6 +47,9 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
expect(subject.parts[1].body.to_s).to include(expected_html)
expect(subject.parts[1].content_type).to include('text/html')
+
+ # Sets issue email participant in sent notification
+ expect(issue.reset.sent_notifications.first.issue_email_participant).to eq(issue_email_participant)
end
end
@@ -209,6 +209,10 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let_it_be(:expected_html) { expected_text }
+ before do
+ issue.update!(external_author: email)
+ end
+
subject { ServiceEmailClass.service_desk_thank_you_email(issue.id) }
it_behaves_like 'a service desk notification email'
@@ -272,9 +276,9 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let(:other_issue) { create(:issue, project: project, description: full_issue_reference) }
let(:template_content) { '%{ISSUE_DESCRIPTION}' }
- let(:expected_template_html) { "<p data-sourcepos=\"1:1-1:22\" dir=\"auto\">#{full_issue_reference}</p>" }
+ let(:expected_template_html) { full_issue_reference }
- subject { ServiceEmailClass.service_desk_thank_you_email(other_issue.id) }
+ subject(:message) { ServiceEmailClass.service_desk_thank_you_email(other_issue.id) }
before do
expect(Gitlab::Template::ServiceDeskTemplate).to receive(:find)
@@ -285,7 +289,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
it 'does not render GitLab-specific-reference links with title attribute' do
- is_expected.to have_body_text(expected_template_html)
+ expect(message.body.to_s).to include(expected_template_html)
end
end
end
@@ -326,7 +330,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let_it_be(:expected_html) { 'My <strong>note</strong>' }
let_it_be(:note) { create(:note_on_issue, noteable: issue, project: project, note: expected_text) }
- subject { ServiceEmailClass.service_desk_new_note_email(issue.id, note.id, email) }
+ subject { ServiceEmailClass.service_desk_new_note_email(issue.id, note.id, issue_email_participant) }
it_behaves_like 'a service desk notification email'
it_behaves_like 'read template from repository', 'new_note'
@@ -466,7 +470,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
let_it_be(:upload_path_1) { "/uploads/#{path_1}" }
let_it_be(:note) { create(:note_on_issue, noteable: issue, project: project, note: "a new comment with [#{filename}](#{upload_path}) [#{filename_1}](#{upload_path_1})") }
- context 'when all uploads processed correct' do
+ context 'when all uploads processed correct' do # rubocop:disable RSpec/MultipleMemoizedHelpers -- Avoid duplication with heavy use of helpers
before do
allow_next_instance_of(FileUploader) do |instance|
allow(instance).to receive(:size).and_return(5.megabytes)
@@ -521,7 +525,7 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
end
context 'when custom email is enabled' do
- subject { Notify.service_desk_new_note_email(issue.id, note.id, email) }
+ subject { Notify.service_desk_new_note_email(issue.id, note.id, issue_email_participant) }
it_behaves_like 'a service desk notification email that uses custom email'
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 34311a8ae22..618717a61df 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -1538,9 +1538,12 @@ RSpec.describe Notify, feature_category: :code_review_workflow do
end
context 'for service desk issues' do
+ let_it_be(:issue_email_participant) do
+ create(:issue_email_participant, issue: issue, email: 'service.desk@example.com')
+ end
+
before do
issue.update!(external_author: 'service.desk@example.com')
- issue.issue_email_participants.create!(email: 'service.desk@example.com')
end
describe 'thank you email', feature_category: :service_desk do
@@ -1615,7 +1618,7 @@ RSpec.describe Notify, feature_category: :code_review_workflow do
describe 'new note email', feature_category: :service_desk do
let_it_be(:first_note) { create(:discussion_note_on_issue, note: 'Hello world') }
- subject { described_class.service_desk_new_note_email(issue.id, first_note.id, 'service.desk@example.com') }
+ subject { described_class.service_desk_new_note_email(issue.id, first_note.id, issue_email_participant) }
it_behaves_like 'an unsubscribeable thread'
it_behaves_like 'appearance header and footer enabled'
diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb
index 5b31e8e5e3c..8da87c2349a 100644
--- a/spec/models/sent_notification_spec.rb
+++ b/spec/models/sent_notification_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe SentNotification, :request_store do
+RSpec.describe SentNotification, :request_store, feature_category: :shared do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
@@ -40,6 +40,12 @@ RSpec.describe SentNotification, :request_store do
end
end
+ describe ' associations' do
+ subject { build(:sent_notification) }
+
+ it { is_expected.to belong_to(:issue_email_participant) }
+ end
+
shared_examples 'a successful sent notification' do
it 'creates a new SentNotification' do
expect { subject }.to change { described_class.count }.by(1)
@@ -61,6 +67,20 @@ RSpec.describe SentNotification, :request_store do
it_behaves_like 'a successful sent notification'
it_behaves_like 'a non-sticky write'
+
+ context 'with issue email participant' do
+ let!(:issue_email_participant) { create(:issue_email_participant, issue: issue) }
+
+ subject(:sent_notification) do
+ described_class.record(issue, user.id, described_class.reply_key, {
+ issue_email_participant: issue_email_participant
+ })
+ end
+
+ it 'saves the issue_email_participant' do
+ expect(sent_notification.issue_email_participant).to eq(issue_email_participant)
+ end
+ end
end
describe '.record_note' do
diff --git a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
deleted file mode 100644
index 717de983871..00000000000
--- a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Update a work item task', feature_category: :team_planning do
- include GraphqlHelpers
-
- let_it_be(:project) { create(:project) }
- let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } }
- let_it_be(:unauthorized_work_item) { create(:work_item) }
- let_it_be(:referenced_work_item, refind: true) { create(:work_item, project: project, title: 'REFERENCED') }
- let_it_be(:parent_work_item) do
- create(:work_item, project: project, description: "- [ ] #{referenced_work_item.to_reference}+")
- end
-
- let(:task) { referenced_work_item }
- let(:work_item) { parent_work_item }
- let(:task_params) { { 'title' => 'UPDATED' } }
- let(:task_input) { { 'id' => task.to_global_id.to_s }.merge(task_params) }
- let(:input) { { 'id' => work_item.to_global_id.to_s, 'taskData' => task_input } }
- let(:mutation) { graphql_mutation(:workItemUpdateTask, input, nil, ['productAnalyticsState']) }
- let(:mutation_response) { graphql_mutation_response(:work_item_update_task) }
-
- context 'the user is not allowed to read a work item' do
- let(:current_user) { create(:user) }
-
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- context 'when user has permissions to update a work item' do
- let(:current_user) { developer }
-
- it 'updates the work item and invalidates markdown cache on the original work item' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- work_item.reload
- referenced_work_item.reload
- end.to change(referenced_work_item, :title).from(referenced_work_item.title).to('UPDATED')
-
- expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response).to include(
- 'workItem' => hash_including(
- 'title' => work_item.title,
- 'descriptionHtml' => a_string_including('UPDATED')
- ),
- 'task' => hash_including(
- 'title' => 'UPDATED'
- )
- )
- end
-
- context 'when providing invalid task params' do
- let(:task_params) { { 'title' => '' } }
-
- it 'makes no changes to the DB and returns an error message' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- work_item.reload
- task.reload
- end.to not_change(task, :title).and(
- not_change(work_item, :description_html)
- )
-
- expect(mutation_response['errors']).to contain_exactly("Title can't be blank")
- end
- end
-
- context 'when user cannot update the task' do
- let(:task) { unauthorized_work_item }
-
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-
- it_behaves_like 'has spam protection' do
- let(:mutation_class) { ::Mutations::WorkItems::UpdateTask }
- end
- end
-
- context 'when user does not have permissions to update a work item' do
- let(:current_user) { developer }
- let(:work_item) { unauthorized_work_item }
-
- it_behaves_like 'a mutation that returns a top-level access error'
- end
-end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 6b949962e53..f2876ddee1b 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -991,6 +991,23 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
end
end
+ context 'updating the `enabled_git_access_protocol` attribute' do
+ %w[ssh http all].each do |protocol|
+ context "with #{protocol}" do
+ subject do
+ put api("/groups/#{group1.id}", user1), params: { enabled_git_access_protocol: protocol }
+ end
+
+ it 'updates the attribute', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['enabled_git_access_protocol']).to eq(protocol)
+ end
+ end
+ end
+ end
+
context 'malicious group name' do
subject { put api("/groups/#{group1.id}", user1), params: { name: "<SCRIPT>alert('DOUBLE-ATTACK!')</SCRIPT>" } }
@@ -2058,6 +2075,19 @@ RSpec.describe API::Groups, feature_category: :groups_and_projects do
end
end
+ context 'when creating a group with `enabled_git_access_protocol' do
+ let(:params) { attributes_for_group_api enabled_git_access_protocol: 'all' }
+
+ subject { post api("/groups", user3), params: params }
+
+ it 'creates group with the specified Git access protocol', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['enabled_git_access_protocol']).to eq(nil)
+ end
+ end
+
it "does not create group, duplicate", :aggregate_failures do
post api("/groups", user3), params: { name: 'Duplicate Test', path: group2.path }
diff --git a/spec/requests/api/usage_data_spec.rb b/spec/requests/api/usage_data_spec.rb
index 37fa75a812c..eb0192d773b 100644
--- a/spec/requests/api/usage_data_spec.rb
+++ b/spec/requests/api/usage_data_spec.rb
@@ -5,6 +5,64 @@ require 'spec_helper'
RSpec.describe API::UsageData, feature_category: :service_ping do
let_it_be(:user) { create(:user) }
+ describe 'GET /usage_data/service_ping' do
+ let(:endpoint) { '/usage_data/service_ping' }
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(usage_data_api: false)
+ end
+
+ it 'returns not_found' do
+ get api(endpoint)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'without authentication' do
+ it 'returns 401 response' do
+ get api(endpoint)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'when authenticated as non-admin' do
+ let(:user) { create(:user) }
+
+ it 'returns 403' do
+ get api(endpoint, user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when authenticated as an admin using read_service_ping access token' do
+ let(:scopes) { [Gitlab::Auth::READ_SERVICE_PING_SCOPE] }
+ let(:personal_access_token) { create(:personal_access_token, user: user, scopes: scopes) }
+
+ before do
+ allow(Ability).to receive(:allowed?).and_return(true)
+ end
+
+ it 'returns 200' do
+ get api(endpoint, personal_access_token: personal_access_token)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns service ping payload' do
+ usage_data = { 'key' => 'value' }
+ allow(Rails.cache).to receive(:fetch).and_return(usage_data)
+
+ get api(endpoint, personal_access_token: personal_access_token)
+
+ expect(response.body).to eq(usage_data.to_json)
+ end
+ end
+ end
+
describe 'POST /usage_data/increment_counter' do
let(:endpoint) { '/usage_data/increment_counter' }
let(:known_event) { "diff_searches" }
diff --git a/spec/services/click_house/sync_strategies/base_sync_strategy_spec.rb b/spec/services/click_house/sync_strategies/base_sync_strategy_spec.rb
index eb9324fd24b..af1785a7eb7 100644
--- a/spec/services/click_house/sync_strategies/base_sync_strategy_spec.rb
+++ b/spec/services/click_house/sync_strategies/base_sync_strategy_spec.rb
@@ -128,7 +128,7 @@ RSpec.describe ClickHouse::SyncStrategies::BaseSyncStrategy, feature_category: :
context 'when clickhouse is not configured' do
before do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return({})
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(false)
end
it 'skips execution' do
@@ -138,7 +138,7 @@ RSpec.describe ClickHouse::SyncStrategies::BaseSyncStrategy, feature_category: :
context 'when exclusive lease error happens' do
it 'skips execution' do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return({ main: :some_db })
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(true)
expect(strategy).to receive(:in_lock).and_raise(Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError)
expect(execute).to eq({ status: :skipped })
diff --git a/spec/services/click_house/sync_strategies/event_sync_strategy_spec.rb b/spec/services/click_house/sync_strategies/event_sync_strategy_spec.rb
index 05fcf6ddeb3..80f5b7b30f7 100644
--- a/spec/services/click_house/sync_strategies/event_sync_strategy_spec.rb
+++ b/spec/services/click_house/sync_strategies/event_sync_strategy_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe ClickHouse::SyncStrategies::EventSyncStrategy, feature_category:
describe '#enabled?' do
context 'when the clickhouse database is configured the feature flag is enabled' do
before do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return({ main: :some_db })
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(true)
stub_feature_flags(event_sync_worker_for_click_house: true)
end
@@ -106,7 +106,7 @@ RSpec.describe ClickHouse::SyncStrategies::EventSyncStrategy, feature_category:
context 'when the clickhouse database is not configured' do
before do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return({})
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(false)
end
it 'returns false' do
@@ -116,7 +116,7 @@ RSpec.describe ClickHouse::SyncStrategies::EventSyncStrategy, feature_category:
context 'when the feature flag is disabled' do
before do
- allow(ClickHouse::Client.configuration).to receive(:databases).and_return({ main: :some_db })
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(true)
stub_feature_flags(event_sync_worker_for_click_house: false)
end
diff --git a/spec/services/namespace_settings/update_service_spec.rb b/spec/services/namespace_settings/update_service_spec.rb
index 413a551ca0c..9473b958957 100644
--- a/spec/services/namespace_settings/update_service_spec.rb
+++ b/spec/services/namespace_settings/update_service_spec.rb
@@ -145,6 +145,7 @@ RSpec.describe NamespaceSettings::UpdateService, feature_category: :groups_and_p
where(:setting_key, :setting_changes_from, :setting_changes_to) do
:prevent_sharing_groups_outside_hierarchy | false | true
:new_user_signups_cap | nil | 100
+ :enabled_git_access_protocol | 'all' | 'ssh'
end
with_them do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 15e7f794795..587e5ed25d5 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -581,7 +581,7 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
end
describe 'Notes' do
- context 'issue note' do
+ describe 'issue note' do
let_it_be(:project) { create(:project, :private) }
let_it_be_with_reload(:issue) { create(:issue, project: project, assignees: [assignee]) }
let_it_be(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
@@ -591,26 +591,28 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
subject { notification.new_note(note) }
- context 'issue_email_participants' do
+ describe 'issue_email_participants' do
before do
allow(Notify).to receive(:service_desk_new_note_email)
- .with(Integer, Integer, String).and_return(mailer)
+ .with(Integer, Integer, IssueEmailParticipant).and_return(mailer)
- allow(::Gitlab::Email::IncomingEmail).to receive(:enabled?) { true }
- allow(::Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?) { true }
+ allow(::Gitlab::Email::IncomingEmail).to receive(:enabled?).and_return(true)
+ allow(::Gitlab::Email::IncomingEmail).to receive(:supports_wildcard?).and_return(true)
end
- let(:subject) { described_class.new }
let(:mailer) { double(deliver_later: true) }
let(:issue) { create(:issue, author: Users::Internal.support_bot) }
let(:project) { issue.project }
let(:note) { create(:note, noteable: issue, project: project) }
+ subject(:notification_service) { described_class.new }
+
shared_examples 'notification with exact metric events' do |number_of_events|
it 'adds metric event' do
metric_transaction = double('Gitlab::Metrics::WebTransaction', increment: true, observe: true)
allow(::Gitlab::Metrics::BackgroundTransaction).to receive(:current).and_return(metric_transaction)
- expect(metric_transaction).to receive(:add_event).with(:service_desk_new_note_email).exactly(number_of_events).times
+ expect(metric_transaction).to receive(:add_event)
+ .with(:service_desk_new_note_email).exactly(number_of_events).times
subject.new_note(note)
end
@@ -638,9 +640,9 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
it 'sends the email' do
expect(Notify).to receive(:service_desk_new_note_email)
- .with(issue.id, note.id, issue.external_author)
+ .with(issue.id, note.id, issue_email_participant)
- subject.new_note(note)
+ notification_service.new_note(note)
end
it_behaves_like 'notification with exact metric events', 1
@@ -652,6 +654,71 @@ RSpec.describe NotificationService, :mailer, feature_category: :team_planning do
it_behaves_like 'no participants are notified'
end
+
+ context 'with multiple external participants' do
+ let!(:other_external_participant) { issue.issue_email_participants.create!(email: 'user@example.com') }
+
+ it 'sends emails' do
+ expect(Notify).to receive(:service_desk_new_note_email)
+ .with(issue.id, note.id, IssueEmailParticipant).twice
+
+ notification_service.new_note(note)
+ end
+
+ context 'when note is from an external participant' do
+ shared_examples 'only sends one Service Desk notification email' do
+ it 'sends one email' do
+ expect(Notify).not_to receive(:service_desk_new_note_email)
+ .with(issue.id, note.id, non_recipient)
+
+ expect(Notify).to receive(:service_desk_new_note_email)
+ .with(issue.id, note.id, recipient)
+
+ notification_service.new_note(note)
+ end
+ end
+
+ let!(:note) do
+ create(
+ :note_on_issue,
+ author: Users::Internal.support_bot,
+ noteable: issue,
+ project_id: issue.project_id,
+ note: '@mention referenced, @unsubscribed_mentioned and @outsider also'
+ )
+ end
+
+ context 'and the note is from the external issue author' do
+ let(:non_recipient) { issue_email_participant }
+ let(:recipient) { other_external_participant }
+ let!(:note_metadata) do
+ create(:note_metadata, note: note, email_participant: issue_email_participant.email)
+ end
+
+ it_behaves_like 'only sends one Service Desk notification email'
+ end
+
+ context 'and the note is from another external participant' do
+ let(:non_recipient) { other_external_participant }
+ let(:recipient) { issue_email_participant }
+ let!(:note_metadata) do
+ create(:note_metadata, note: note, email_participant: other_external_participant.email)
+ end
+
+ it_behaves_like 'only sends one Service Desk notification email'
+
+ context 'and the external note auhor email has different format' do
+ let(:non_recipient) { other_external_participant }
+ let(:recipient) { issue_email_participant }
+ let!(:note_metadata) do
+ create(:note_metadata, note: note, email_participant: 'USER@example.com')
+ end
+
+ it_behaves_like 'only sends one Service Desk notification email'
+ end
+ end
+ end
+ end
end
context 'do exist and note is confidential' do
diff --git a/spec/services/work_items/widgets/labels_service/create_service_spec.rb b/spec/services/work_items/widgets/labels_service/create_service_spec.rb
new file mode 100644
index 00000000000..70b185b9301
--- /dev/null
+++ b/spec/services/work_items/widgets/labels_service/create_service_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::LabelsService::CreateService, feature_category: :team_planning do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:label1) { create(:label, project: project) }
+ let_it_be(:label2) { create(:label, project: project) }
+ let_it_be(:label3) { create(:label, project: project) }
+ let_it_be(:current_user) { create(:user).tap { |user| project.add_reporter(user) } }
+
+ let(:work_item) { create(:work_item, project: project, labels: [label1, label2]) }
+ let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Labels) } }
+ let(:service) { described_class.new(widget: widget, current_user: current_user) }
+
+ describe '#prepare_create_params' do
+ context 'when params are set' do
+ let(:params) { { add_label_ids: [label1.id], label_ids: [label2.id] } }
+
+ it "sets params correctly" do
+ expect(service.prepare_create_params(params: params)).to include(
+ {
+ add_label_ids: match_array([label1.id]),
+ label_ids: match_array([label2.id])
+ }
+ )
+ end
+
+ context "and user doesn't have permissions to update labels" do
+ let_it_be(:current_user) { create(:user) }
+
+ it 'removes label params' do
+ expect(service.prepare_create_params(params: params)).to be_nil
+ end
+ end
+ end
+
+ context 'when widget does not exist in new type' do
+ let(:params) { {} }
+
+ before do
+ allow(service).to receive(:new_type_excludes_widget?).and_return(true)
+ end
+
+ it "sets label params as empty" do
+ expect(service.prepare_create_params(params: params)).to include(
+ {
+ add_label_ids: [],
+ label_ids: []
+ }
+ )
+ end
+ end
+ end
+end
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 66730340f84..91d423fcd67 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -4340,7 +4340,6 @@
- './spec/graphql/mutations/todos/restore_many_spec.rb'
- './spec/graphql/mutations/todos/restore_spec.rb'
- './spec/graphql/mutations/user_callouts/create_spec.rb'
-- './spec/graphql/mutations/work_items/update_task_spec.rb'
- './spec/graphql/resolvers/admin/analytics/usage_trends/measurements_resolver_spec.rb'
- './spec/graphql/resolvers/alert_management/alert_resolver_spec.rb'
- './spec/graphql/resolvers/alert_management/alert_status_counts_resolver_spec.rb'
@@ -6221,7 +6220,6 @@
- './spec/lib/gitlab/hook_data/subgroup_builder_spec.rb'
- './spec/lib/gitlab/hook_data/user_builder_spec.rb'
- './spec/lib/gitlab/hotlinking_detector_spec.rb'
-- './spec/lib/gitlab/http_connection_adapter_spec.rb'
- './spec/lib/gitlab/http_io_spec.rb'
- './spec/lib/gitlab/http_spec.rb'
- './spec/lib/gitlab/i18n/metadata_entry_spec.rb'
@@ -7924,7 +7922,6 @@
- './spec/requests/api/graphql/mutations/work_items/create_spec.rb'
- './spec/requests/api/graphql/mutations/work_items/delete_spec.rb'
- './spec/requests/api/graphql/mutations/work_items/update_spec.rb'
-- './spec/requests/api/graphql/mutations/work_items/update_task_spec.rb'
- './spec/requests/api/graphql/namespace/package_settings_spec.rb'
- './spec/requests/api/graphql/namespace/projects_spec.rb'
- './spec/requests/api/graphql/namespace_query_spec.rb'
diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
index c6ea665a160..ec0d1e1a976 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -78,6 +78,7 @@ RSpec.shared_context 'GroupPolicy context' do
read_billing
edit_billing
admin_member_access_request
+ update_git_access_protocol
]
end
diff --git a/spec/workers/click_house/event_authors_consistency_cron_worker_spec.rb b/spec/workers/click_house/event_authors_consistency_cron_worker_spec.rb
index 4d7e0e138e9..a66657c639f 100644
--- a/spec/workers/click_house/event_authors_consistency_cron_worker_spec.rb
+++ b/spec/workers/click_house/event_authors_consistency_cron_worker_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe ClickHouse::EventAuthorsConsistencyCronWorker, feature_category:
context 'when ClickHouse is disabled' do
it 'does nothing' do
- allow(ClickHouse::Client).to receive(:database_configured?).and_return(false)
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(false)
expect(worker).not_to receive(:log_extra_metadata_on_done)
@@ -17,7 +17,7 @@ RSpec.describe ClickHouse::EventAuthorsConsistencyCronWorker, feature_category:
context 'when the event_sync_worker_for_click_house feature flag is off' do
it 'does nothing' do
- allow(ClickHouse::Client).to receive(:database_configured?).and_return(true)
+ allow(Gitlab::ClickHouse).to receive(:configured?).and_return(true)
stub_feature_flags(event_sync_worker_for_click_house: false)
expect(worker).not_to receive(:log_extra_metadata_on_done)
diff --git a/workhorse/internal/helper/command/command.go b/workhorse/internal/helper/command/command.go
index 59c8c9a3db2..67d6838b170 100644
--- a/workhorse/internal/helper/command/command.go
+++ b/workhorse/internal/helper/command/command.go
@@ -15,9 +15,9 @@ func ExitStatus(err error) (int, bool) {
}
}
-func KillProcessGroup(cmd *exec.Cmd) {
+func KillProcessGroup(cmd *exec.Cmd) error {
if cmd == nil {
- return
+ return nil
}
if p := cmd.Process; p != nil && p.Pid > 0 {
@@ -26,5 +26,5 @@ func KillProcessGroup(cmd *exec.Cmd) {
}
// reap our child process
- cmd.Wait()
+ return cmd.Wait()
}
diff --git a/workhorse/internal/helper/command/command_test.go b/workhorse/internal/helper/command/command_test.go
new file mode 100644
index 00000000000..2f25f09373c
--- /dev/null
+++ b/workhorse/internal/helper/command/command_test.go
@@ -0,0 +1,97 @@
+package command
+
+import (
+ "errors"
+ "os/exec"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+type ErrorWithExitCode struct {
+ exitCode int
+}
+
+func (e ErrorWithExitCode) Error() string {
+ return "Error that responds to ExitCode()"
+}
+
+func (e ErrorWithExitCode) ExitCode() int {
+ return e.exitCode
+}
+
+func TestExitStatus(t *testing.T) {
+ tests := []struct {
+ name string
+ err error
+ exitCode int
+ ok bool
+ }{
+ {
+ name: "error responds to ExitCode()",
+ err: ErrorWithExitCode{exitCode: 0},
+ exitCode: 0,
+ ok: true,
+ },
+ {
+ name: "error is not nil",
+ err: errors.New("some generic error"),
+ exitCode: -1,
+ ok: false,
+ },
+ {
+ name: "else",
+ err: nil,
+ exitCode: 0,
+ ok: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ exitCode, ok := ExitStatus(tt.err)
+
+ require.Equal(t, tt.exitCode, exitCode)
+ require.Equal(t, tt.ok, ok)
+ })
+ }
+}
+
+func TestKillProcessGroup(t *testing.T) {
+ tests := []struct {
+ name string
+ cmd *exec.Cmd
+ start bool
+ err error
+ }{
+ {
+ name: "command is nil",
+ cmd: nil,
+ start: false,
+ err: nil,
+ },
+ {
+ name: "command not started",
+ cmd: exec.Command("sleep"),
+ start: false,
+ err: errors.New(""),
+ },
+ {
+ name: "command started",
+ cmd: exec.Command("sleep"),
+ start: true,
+ err: &exec.ExitError{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if tt.start == true {
+ tt.cmd.Start()
+ }
+
+ err := KillProcessGroup(tt.cmd)
+ require.IsType(t, tt.err, err)
+ })
+ }
+}