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>2023-01-25 21:08:56 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-01-25 21:08:56 +0300
commitff549ec680715e4ea1daf0cee457f29dfe3b6062 (patch)
tree823fc28718a1278025ee2d88c1368958befec4da
parentec558ad8ed732ff6f8a89aa3651eb92c27c50deb (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml4
-rw-r--r--.rubocop_todo/rspec/missing_feature_category.yml44
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.checksum10
-rw-r--r--Gemfile.lock18
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_jobs_table.vue4
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql9
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_item.vue17
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue5
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/show/index.js2
-rw-r--r--app/assets/javascripts/projects/commit/store/getters.js4
-rw-r--r--app/assets/javascripts/projects/merge_requests/index.js23
-rw-r--r--app/assets/javascripts/projects/report_abuse/components/report_abuse_dropdown_item.vue (renamed from app/assets/javascripts/projects/merge_requests/components/report_abuse_dropdown_item.vue)0
-rw-r--r--app/assets/javascripts/projects/report_abuse/index.js25
-rw-r--r--app/assets/javascripts/releases/components/release_block_assets.vue2
-rw-r--r--app/assets/javascripts/snippet/snippet_show.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue6
-rw-r--r--app/assets/stylesheets/page_bundles/incidents.scss6
-rw-r--r--app/helpers/issuables_helper.rb2
-rw-r--r--app/helpers/sessions_helper.rb7
-rw-r--r--app/models/issue_email_participant.rb1
-rw-r--r--app/models/namespace.rb26
-rw-r--r--app/models/namespaces/randomized_suffix_path.rb39
-rw-r--r--app/models/repository.rb4
-rw-r--r--app/policies/project_policy.rb1
-rw-r--r--app/presenters/issue_email_participant_presenter.rb12
-rw-r--r--app/presenters/issue_presenter.rb13
-rw-r--r--app/serializers/issue_entity.rb11
-rw-r--r--app/serializers/note_entity.rb4
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml2
-rw-r--r--app/views/projects/notes/_more_actions_dropdown.html.haml5
-rw-r--r--app/views/shared/notes/_notes_with_form.html.haml2
-rw-r--r--config/feature_flags/development/commit_search_trailing_spaces.yml8
-rw-r--r--doc/administration/auth/ldap/index.md5
-rw-r--r--doc/development/application_slis/rails_request_apdex.md3
-rw-r--r--doc/development/ee_features.md4
-rw-r--r--doc/development/go_guide/index.md2
-rw-r--r--doc/integration/advanced_search/elasticsearch.md2
-rw-r--r--doc/operations/incident_management/integrations.md173
-rw-r--r--doc/topics/offline/quick_start_guide.md2
-rw-r--r--doc/user/admin_area/credentials_inventory.md6
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md10
-rw-r--r--doc/user/application_security/get-started-security.md6
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md6
-rw-r--r--doc/user/clusters/management_project_template.md4
-rw-r--r--doc/user/packages/rubygems_registry/index.md2
-rw-r--r--doc/user/profile/index.md2
-rw-r--r--doc/user/project/code_intelligence.md2
-rw-r--r--doc/user/project/highlighting.md2
-rw-r--r--doc/user/project/members/index.md29
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md4
-rw-r--r--doc/user/project/service_desk.md9
-rw-r--r--lib/api/internal/kubernetes.rb4
-rw-r--r--lib/gitlab.rb15
-rw-r--r--lib/gitlab/slug/path.rb43
-rw-r--r--lib/gitlab/utils/email.rb28
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb42
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb1
-rw-r--r--spec/features/projects/issues/email_participants_spec.rb44
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb4
-rw-r--r--spec/frontend/abuse_reports/components/abuse_category_selector_spec.js2
-rw-r--r--spec/frontend/ci/runner/components/runner_jobs_table_spec.js8
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js19
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js18
-rw-r--r--spec/frontend/notes/components/note_actions_spec.js8
-rw-r--r--spec/frontend/projects/commit/mock_data.js6
-rw-r--r--spec/frontend/projects/commit/store/getters_spec.js8
-rw-r--r--spec/frontend/projects/report_abuse/components/report_abuse_dropdown_item_spec.js (renamed from spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js)2
-rw-r--r--spec/frontend/releases/components/release_block_assets_spec.js36
-rw-r--r--spec/frontend/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports_spec.js7
-rw-r--r--spec/helpers/issuables_helper_spec.rb35
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb4
-rw-r--r--spec/lib/gitlab/slug/path_spec.rb33
-rw-r--r--spec/lib/gitlab/utils/email_spec.rb42
-rw-r--r--spec/lib/gitlab_spec.rb82
-rw-r--r--spec/lib/service_ping/build_payload_spec.rb2
-rw-r--r--spec/models/ci_platform_metric_spec.rb2
-rw-r--r--spec/models/concerns/bulk_insert_safe_spec.rb2
-rw-r--r--spec/models/design_management/design_spec.rb2
-rw-r--r--spec/models/issue_email_participant_spec.rb6
-rw-r--r--spec/models/merge_request_diff_commit_spec.rb2
-rw-r--r--spec/models/merge_request_diff_file_spec.rb2
-rw-r--r--spec/models/namespace_spec.rb17
-rw-r--r--spec/models/namespaces/randomized_suffix_path_spec.rb37
-rw-r--r--spec/models/repository_spec.rb10
-rw-r--r--spec/presenters/issue_email_participant_presenter_spec.rb59
-rw-r--r--spec/presenters/issue_presenter_spec.rb74
-rw-r--r--spec/serializers/issue_entity_spec.rb52
-rw-r--r--spec/services/notes/create_service_spec.rb8
-rw-r--r--spec/services/packages/debian/generate_distribution_service_spec.rb2
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb2
-rw-r--r--spec/support/shared_examples/features/reportable_note_shared_examples.rb22
-rw-r--r--spec/support/shared_examples/integrations/integration_settings_form.rb2
-rw-r--r--spec/support/shared_examples/serializers/note_entity_shared_examples.rb4
-rw-r--r--spec/views/projects/issues/_issue.html.haml_spec.rb53
-rw-r--r--spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb5
-rw-r--r--spec/workers/packages/debian/generate_distribution_worker_spec.rb3
99 files changed, 1018 insertions, 441 deletions
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index f394851193c..54bb5d459e0 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -429,6 +429,7 @@ Gitlab/NamespacedClass:
- 'app/presenters/group_clusterable_presenter.rb'
- 'app/presenters/group_member_presenter.rb'
- 'app/presenters/instance_clusterable_presenter.rb'
+ - 'app/presenters/issue_email_participant_presenter.rb'
- 'app/presenters/issue_presenter.rb'
- 'app/presenters/label_presenter.rb'
- 'app/presenters/member_presenter.rb'
@@ -1266,10 +1267,7 @@ Gitlab/NamespacedClass:
- 'spec/lib/bitbucket/collection_spec.rb'
- 'spec/lib/gitlab/multi_destination_logger_spec.rb'
- 'spec/lib/marginalia_spec.rb'
- - 'spec/mailers/notify_spec.rb'
- 'spec/models/concerns/batch_destroy_dependent_associations_spec.rb'
- - 'spec/models/concerns/bulk_insertable_associations_spec.rb'
- - 'spec/models/concerns/triggerable_hooks_spec.rb'
- 'spec/support/helpers/ci_artifact_metadata_generator.rb'
- 'spec/support/helpers/fake_migration_classes.rb'
- 'spec/support/helpers/fake_u2f_device.rb'
diff --git a/.rubocop_todo/rspec/missing_feature_category.yml b/.rubocop_todo/rspec/missing_feature_category.yml
index a76717d8d3f..fcc75eacbdb 100644
--- a/.rubocop_todo/rspec/missing_feature_category.yml
+++ b/.rubocop_todo/rspec/missing_feature_category.yml
@@ -237,7 +237,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/mutations/compliance_management/frameworks/update_spec.rb'
- 'ee/spec/graphql/mutations/dast/profiles/delete_spec.rb'
- 'ee/spec/graphql/mutations/dast/profiles/run_spec.rb'
- - 'ee/spec/graphql/mutations/dast/profiles/update_spec.rb'
- 'ee/spec/graphql/mutations/dast_on_demand_scans/create_spec.rb'
- 'ee/spec/graphql/mutations/dast_scanner_profiles/delete_spec.rb'
- 'ee/spec/graphql/mutations/dast_site_profiles/create_spec.rb'
@@ -404,7 +403,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/graphql/types/dast/scan_method_type_enum_spec.rb'
- 'ee/spec/graphql/types/dast/site_profile_auth_input_type_spec.rb'
- 'ee/spec/graphql/types/dast/site_profile_auth_type_spec.rb'
- - 'ee/spec/graphql/types/dast_scanner_profile_type_spec.rb'
- 'ee/spec/graphql/types/dast_site_profile_type_spec.rb'
- 'ee/spec/graphql/types/dast_site_validation_type_spec.rb'
- 'ee/spec/graphql/types/deployments/approval_summary_spec.rb'
@@ -1064,7 +1062,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/geo/replicator_spec.rb'
- 'ee/spec/lib/gitlab/geo/signed_data_spec.rb'
- 'ee/spec/lib/gitlab/geo_spec.rb'
- - 'ee/spec/lib/gitlab/git_access_spec.rb'
- 'ee/spec/lib/gitlab/git_access_wiki_spec.rb'
- 'ee/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb'
- 'ee/spec/lib/gitlab/gl_repository/identifier_spec.rb'
@@ -1200,6 +1197,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/lib/gitlab/web_ide/config/entry/schema/uri_spec.rb'
- 'ee/spec/lib/gitlab/web_ide/config/entry/schema_spec.rb'
- 'ee/spec/lib/gitlab/web_ide/config/entry/schemas_spec.rb'
+ - 'ee/spec/lib/gitlab_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'
@@ -1367,7 +1365,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/models/ee/event_spec.rb'
- 'ee/spec/models/ee/gpg_key_spec.rb'
- 'ee/spec/models/ee/group_group_link_spec.rb'
- - 'ee/spec/models/ee/group_spec.rb'
- 'ee/spec/models/ee/groups/feature_setting_spec.rb'
- 'ee/spec/models/ee/incident_management/project_incident_management_setting_spec.rb'
- 'ee/spec/models/ee/integration_spec.rb'
@@ -1600,7 +1597,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/policies/instance_security_dashboard_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/merge_requests/external_status_check_policy_spec.rb'
- 'ee/spec/policies/note_policy_spec.rb'
- 'ee/spec/policies/path_lock_policy_spec.rb'
@@ -1756,10 +1752,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/analytics/cycle_analytics/aggregator_service_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/consistency_check_service_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/data_loader_service_spec.rb'
- - 'ee/spec/services/analytics/cycle_analytics/stages/create_service_spec.rb'
- - 'ee/spec/services/analytics/cycle_analytics/stages/delete_service_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb'
- - 'ee/spec/services/analytics/cycle_analytics/stages/update_service_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/value_streams/create_service_spec.rb'
- 'ee/spec/services/analytics/cycle_analytics/value_streams/update_service_spec.rb'
- 'ee/spec/services/analytics/devops_adoption/enabled_namespaces/bulk_delete_service_spec.rb'
@@ -1776,9 +1769,7 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/app_sec/dast/profiles/audit/update_service_spec.rb'
- 'ee/spec/services/app_sec/dast/profiles/build_config_service_spec.rb'
- 'ee/spec/services/app_sec/dast/profiles/create_associations_service_spec.rb'
- - 'ee/spec/services/app_sec/dast/profiles/create_service_spec.rb'
- 'ee/spec/services/app_sec/dast/profiles/destroy_service_spec.rb'
- - 'ee/spec/services/app_sec/dast/profiles/update_service_spec.rb'
- 'ee/spec/services/app_sec/dast/scan_configs/fetch_service_spec.rb'
- 'ee/spec/services/app_sec/dast/scans/create_service_spec.rb'
- 'ee/spec/services/app_sec/dast/scans/run_service_spec.rb'
@@ -1941,7 +1932,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/after_update_service_spec.rb'
- 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/create_service_spec.rb'
- 'ee/spec/services/ee/incident_management/issuable_escalation_statuses/prepare_update_service_spec.rb'
- - 'ee/spec/services/ee/integrations/slack_interactions/incident_management/incident_modal_opened_service_spec.rb'
- 'ee/spec/services/ee/integrations/test/project_service_spec.rb'
- 'ee/spec/services/ee/ip_restrictions/update_service_spec.rb'
- 'ee/spec/services/ee/issuable/bulk_update_service_spec.rb'
@@ -1980,7 +1970,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/ee/notes/post_process_service_spec.rb'
- 'ee/spec/services/ee/notes/quick_actions_service_spec.rb'
- 'ee/spec/services/ee/notes/update_service_spec.rb'
- - 'ee/spec/services/ee/notification_service_spec.rb'
- 'ee/spec/services/ee/null_notification_service_spec.rb'
- 'ee/spec/services/ee/personal_access_tokens/revoke_service_spec.rb'
- 'ee/spec/services/ee/post_receive_service_spec.rb'
@@ -2362,7 +2351,6 @@ RSpec/MissingFeatureCategory:
- 'ee/spec/services/work_items/widgets/weight_service/update_service_spec.rb'
- 'ee/spec/tasks/geo/git_rake_spec.rb'
- 'ee/spec/tasks/gitlab/check_rake_spec.rb'
- - 'ee/spec/tasks/gitlab/elastic_rake_spec.rb'
- 'ee/spec/tasks/gitlab/license_rake_spec.rb'
- 'ee/spec/tasks/gitlab/seed/group_seed_rake_spec.rb'
- 'ee/spec/tasks/gitlab/spdx_rake_spec.rb'
@@ -2864,7 +2852,6 @@ RSpec/MissingFeatureCategory:
- 'qa/qa/specs/features/ee/browser_ui/10_govern/vulnerability_management_spec.rb'
- '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/free_trial_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/purchase/overage_modal_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/purchase/purchase_ci_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/11_fulfillment/purchase/purchase_storage_spec.rb'
@@ -3222,7 +3209,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/discussions_controller_spec.rb'
- 'spec/controllers/projects/environments/prometheus_api_controller_spec.rb'
- 'spec/controllers/projects/environments/sample_metrics_controller_spec.rb'
- - 'spec/controllers/projects/environments_controller_spec.rb'
- 'spec/controllers/projects/error_tracking/projects_controller_spec.rb'
- 'spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb'
- 'spec/controllers/projects/error_tracking_controller_spec.rb'
@@ -3290,7 +3276,6 @@ RSpec/MissingFeatureCategory:
- 'spec/controllers/projects/web_ide_terminals_controller_spec.rb'
- 'spec/controllers/projects/wikis_controller_spec.rb'
- 'spec/controllers/projects_controller_spec.rb'
- - 'spec/controllers/registrations_controller_spec.rb'
- 'spec/controllers/repositories/git_http_controller_spec.rb'
- 'spec/controllers/repositories/lfs_storage_controller_spec.rb'
- 'spec/controllers/root_controller_spec.rb'
@@ -4115,7 +4100,6 @@ RSpec/MissingFeatureCategory:
- 'spec/helpers/integrations_helper_spec.rb'
- 'spec/helpers/invite_members_helper_spec.rb'
- 'spec/helpers/issuables_description_templates_helper_spec.rb'
- - 'spec/helpers/issuables_helper_spec.rb'
- 'spec/helpers/issues_helper_spec.rb'
- 'spec/helpers/jira_connect_helper_spec.rb'
- 'spec/helpers/json_helper_spec.rb'
@@ -4673,7 +4657,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb'
- - 'spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_topics_title_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_upvotes_count_on_issues_spec.rb'
- 'spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb'
@@ -4943,7 +4926,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/ci/parsers_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/assign_partition_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/build_spec.rb'
- - 'spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/command_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb'
- 'spec/lib/gitlab/ci/pipeline/chain/create_spec.rb'
@@ -5491,7 +5473,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/git_access_design_spec.rb'
- 'spec/lib/gitlab/git_access_project_spec.rb'
- 'spec/lib/gitlab/git_access_snippet_spec.rb'
- - 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/git_access_wiki_spec.rb'
- 'spec/lib/gitlab/git_post_receive_spec.rb'
- 'spec/lib/gitlab/git_ref_validator_spec.rb'
@@ -5523,7 +5504,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/importer/attachments/notes_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/attachments/releases_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/diff_note_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/diff_notes_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/events/base_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/events/changed_assignee_spec.rb'
- 'spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb'
@@ -5535,22 +5515,15 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/importer/events/reopened_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issue_and_label_links_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issue_event_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/issue_events_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/issue_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/label_links_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/note_attachments_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/note_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/notes_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/importer/pull_requests_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_requests_merged_by_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/pull_requests_reviews_importer_spec.rb'
- 'spec/lib/gitlab/github_import/importer/repository_importer_spec.rb'
@@ -5566,7 +5539,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/github_import/milestone_finder_spec.rb'
- 'spec/lib/gitlab/github_import/object_counter_spec.rb'
- 'spec/lib/gitlab/github_import/parallel_importer_spec.rb'
- - 'spec/lib/gitlab/github_import/parallel_scheduling_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_note_spec.rb'
- 'spec/lib/gitlab/github_import/representation/diff_notes/suggestion_formatter_spec.rb'
- 'spec/lib/gitlab/github_import/representation/expose_attribute_spec.rb'
@@ -5743,7 +5715,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb'
- 'spec/lib/gitlab/import_export/project/sample/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'
- 'spec/lib/gitlab/import_export/project/tree_saver_spec.rb'
- 'spec/lib/gitlab/import_export/reader_spec.rb'
- 'spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb'
@@ -5787,7 +5758,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/jira_import/labels_importer_spec.rb'
- 'spec/lib/gitlab/jira_import/metadata_collector_spec.rb'
- 'spec/lib/gitlab/jira_import_spec.rb'
- - 'spec/lib/gitlab/job_waiter_spec.rb'
- 'spec/lib/gitlab/json_cache_spec.rb'
- 'spec/lib/gitlab/json_logger_spec.rb'
- 'spec/lib/gitlab/json_spec.rb'
@@ -5944,7 +5914,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/metrics_spec.rb'
- 'spec/lib/gitlab/middleware/basic_health_check_spec.rb'
- 'spec/lib/gitlab/middleware/compressed_json_spec.rb'
- - 'spec/lib/gitlab/middleware/go_spec.rb'
- 'spec/lib/gitlab/middleware/handle_ip_spoof_attack_error_spec.rb'
- 'spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb'
- 'spec/lib/gitlab/middleware/memory_report_spec.rb'
@@ -6076,7 +6045,6 @@ RSpec/MissingFeatureCategory:
- 'spec/lib/gitlab/reactive_cache_set_cache_spec.rb'
- 'spec/lib/gitlab/redis/boolean_spec.rb'
- 'spec/lib/gitlab/redis/cache_spec.rb'
- - 'spec/lib/gitlab/redis/duplicate_jobs_spec.rb'
- 'spec/lib/gitlab/redis/hll_spec.rb'
- 'spec/lib/gitlab/redis/queues_spec.rb'
- 'spec/lib/gitlab/redis/rate_limiting_spec.rb'
@@ -6689,7 +6657,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/concerns/ci/artifactable_spec.rb'
- 'spec/models/concerns/ci/bulk_insertable_tags_spec.rb'
- 'spec/models/concerns/ci/has_ref_spec.rb'
- - 'spec/models/concerns/ci/has_status_spec.rb'
- 'spec/models/concerns/ci/has_variable_spec.rb'
- 'spec/models/concerns/ci/maskable_spec.rb'
- 'spec/models/concerns/ci/partitionable/switch_spec.rb'
@@ -6737,7 +6704,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/concerns/mentionable_spec.rb'
- 'spec/models/concerns/milestoneable_spec.rb'
- 'spec/models/concerns/milestoneish_spec.rb'
- - 'spec/models/concerns/noteable_spec.rb'
- 'spec/models/concerns/nullify_if_blank_spec.rb'
- 'spec/models/concerns/optionally_search_spec.rb'
- 'spec/models/concerns/participable_spec.rb'
@@ -6804,7 +6770,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/deployment_cluster_spec.rb'
- 'spec/models/deployment_merge_request_spec.rb'
- 'spec/models/deployment_metrics_spec.rb'
- - 'spec/models/deployment_spec.rb'
- 'spec/models/description_version_spec.rb'
- 'spec/models/design_management/action_spec.rb'
- 'spec/models/design_management/design_action_spec.rb'
@@ -6979,7 +6944,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/namespace/root_storage_statistics_spec.rb'
- 'spec/models/namespace/traversal_hierarchy_spec.rb'
- 'spec/models/namespace_ci_cd_setting_spec.rb'
- - 'spec/models/namespace_spec.rb'
- 'spec/models/namespace_statistics_spec.rb'
- 'spec/models/namespaces/project_namespace_spec.rb'
- 'spec/models/namespaces/sync_event_spec.rb'
@@ -7076,7 +7040,6 @@ RSpec/MissingFeatureCategory:
- 'spec/models/project_setting_spec.rb'
- 'spec/models/project_snippet_spec.rb'
- 'spec/models/project_statistics_spec.rb'
- - 'spec/models/project_team_spec.rb'
- 'spec/models/project_wiki_spec.rb'
- 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
- 'spec/models/projects/ci_feature_usage_spec.rb'
@@ -7813,7 +7776,6 @@ RSpec/MissingFeatureCategory:
- 'spec/services/ci/pipeline_bridge_status_service_spec.rb'
- 'spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb'
- 'spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb'
- - 'spec/services/ci/pipeline_schedule_service_spec.rb'
- 'spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb'
- 'spec/services/ci/pipeline_trigger_service_spec.rb'
- 'spec/services/ci/pipelines/add_job_service_spec.rb'
@@ -8071,7 +8033,6 @@ RSpec/MissingFeatureCategory:
- 'spec/services/merge_requests/after_create_service_spec.rb'
- 'spec/services/merge_requests/approval_service_spec.rb'
- 'spec/services/merge_requests/assign_issues_service_spec.rb'
- - 'spec/services/merge_requests/build_service_spec.rb'
- 'spec/services/merge_requests/cleanup_refs_service_spec.rb'
- 'spec/services/merge_requests/close_service_spec.rb'
- 'spec/services/merge_requests/conflicts/list_service_spec.rb'
@@ -8189,7 +8150,6 @@ RSpec/MissingFeatureCategory:
- 'spec/services/packages/debian/generate_distribution_service_spec.rb'
- 'spec/services/packages/debian/parse_debian822_service_spec.rb'
- 'spec/services/packages/debian/process_changes_service_spec.rb'
- - 'spec/services/packages/debian/process_package_file_service_spec.rb'
- 'spec/services/packages/debian/sign_distribution_service_spec.rb'
- 'spec/services/packages/debian/update_distribution_service_spec.rb'
- 'spec/services/packages/generic/create_package_file_service_spec.rb'
@@ -8335,7 +8295,6 @@ RSpec/MissingFeatureCategory:
- 'spec/services/protected_tags/destroy_service_spec.rb'
- 'spec/services/protected_tags/update_service_spec.rb'
- 'spec/services/push_event_payload_service_spec.rb'
- - 'spec/services/quick_actions/interpret_service_spec.rb'
- 'spec/services/quick_actions/target_service_spec.rb'
- 'spec/services/releases/create_evidence_service_spec.rb'
- 'spec/services/releases/create_service_spec.rb'
@@ -8412,7 +8371,6 @@ RSpec/MissingFeatureCategory:
- 'spec/services/todos/destroy/confidential_issue_service_spec.rb'
- 'spec/services/todos/destroy/design_service_spec.rb'
- 'spec/services/todos/destroy/destroyed_issuable_service_spec.rb'
- - 'spec/services/todos/destroy/entity_leave_service_spec.rb'
- 'spec/services/todos/destroy/group_private_service_spec.rb'
- 'spec/services/todos/destroy/project_private_service_spec.rb'
- 'spec/services/todos/destroy/unauthorized_features_service_spec.rb'
diff --git a/Gemfile b/Gemfile
index c50ba869258..2d68e7d6f1c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -346,7 +346,7 @@ gem 'gitlab-labkit', '~> 0.29.0'
gem 'thrift', '>= 0.16.0'
# I18n
-gem 'ruby_parser', '~> 3.15', require: false
+gem 'ruby_parser', '~> 3.19', require: false
gem 'rails-i18n', '~> 7.0'
gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3'
@@ -387,7 +387,7 @@ group :development, :test do
gem 'bullet', '~> 7.0.2'
gem 'pry-byebug'
gem 'pry-rails', '~> 0.3.9'
- gem 'pry-shell', '~> 0.5.1'
+ gem 'pry-shell', '~> 0.6.0'
gem 'awesome_print', require: false
diff --git a/Gemfile.checksum b/Gemfile.checksum
index 93f1a2f2ceb..77c870cf18d 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -383,7 +383,7 @@
{"name":"octokit","version":"4.25.1","platform":"ruby","checksum":"c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96"},
{"name":"ohai","version":"16.10.6","platform":"ruby","checksum":"b835806e585faea4ac8346b68c722fb5fc29a29f73fd7e3a022f9073132dec22"},
{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
-{"name":"oj-introspect","version":"0.7.1","platform":"ruby","checksum":"ea584e78495a62d5356aece7242bb55455d623ad3deb3cd778e623dd19e050c0"},
+{"name":"oj-introspect","version":"0.7.2","platform":"ruby","checksum":"c415a44567ed2870d8e963a69421d9322128e194fab7867e37e54d5a25d5333d"},
{"name":"omniauth","version":"2.1.0","platform":"ruby","checksum":"bff7234f5ec9323622b217c7f26d52f850de0b0e2b8c807c3358fc79fe572300"},
{"name":"omniauth-alicloud","version":"2.0.1","platform":"ruby","checksum":"b14c425bca02b4d0f73e710ceb62c0f1f8533e0c427c1c495d2b40f87b3f48d3"},
{"name":"omniauth-atlassian-oauth2","version":"0.2.0","platform":"ruby","checksum":"eb07574a188ab8a03376ce288bce86bc2dd4a1382ffa5781cb5e2b7bc15d76c9"},
@@ -434,7 +434,7 @@
{"name":"pry","version":"0.13.1","platform":"ruby","checksum":"1393918c415af46b6d09044d2b78dde92b29bc834fd85c369a950bab0826dc47"},
{"name":"pry-byebug","version":"3.9.0","platform":"ruby","checksum":"3bba08f97fea15b89cc299f3b5136e3b85763cd18cf84960eac4fbfbeb2ede24"},
{"name":"pry-rails","version":"0.3.9","platform":"ruby","checksum":"468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1"},
-{"name":"pry-shell","version":"0.5.1","platform":"ruby","checksum":"2b9000e30677acf5d66f55fa53d31934b7c069d9e0f738a0b84eed03a4ab677d"},
+{"name":"pry-shell","version":"0.6.0","platform":"ruby","checksum":"64a00b584d197dccbf5d7db13f533062012459e97bb35830e577b8377b3b96e8"},
{"name":"public_suffix","version":"5.0.0","platform":"ruby","checksum":"26ee4fbce33ada25eb117ac71f2c24bf4d8b3414ab6b34f05b4708a3e90f1c6b"},
{"name":"puma","version":"5.6.5","platform":"java","checksum":"29d78fc2bc070b9db285a3334a890c3e0ece9bb369388065f0f340ccb1e57faf"},
{"name":"puma","version":"5.6.5","platform":"ruby","checksum":"661029d15a115e9f6c0641a69c830ffd9f1b9ac63fcd0791d94ccd900e03f863"},
@@ -517,7 +517,7 @@
{"name":"ruby-saml","version":"1.13.0","platform":"ruby","checksum":"d31cbdf5fb8fdd6aa3187e48dba3085cfeb751af30276a5739aa3659a66f069c"},
{"name":"ruby-statistics","version":"3.0.0","platform":"ruby","checksum":"610301370346931cb701e3a8d3d3e28eb65681162cae6066c0c11abf20efdc81"},
{"name":"ruby2_keywords","version":"0.0.5","platform":"ruby","checksum":"ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef"},
-{"name":"ruby_parser","version":"3.15.0","platform":"ruby","checksum":"53784028e46407d43b5a704f10f105db00241102ee4402d2a55755b5fa2ad42c"},
+{"name":"ruby_parser","version":"3.19.2","platform":"ruby","checksum":"aaadcedd9263e6c32e0e667f10d4f97dac0a5de313323d1dbb5db612605ff896"},
{"name":"rubyntlm","version":"0.6.3","platform":"ruby","checksum":"5b321456dba3130351f7451f8669f1afa83a0d26fd63cdec285b7b88e667102d"},
{"name":"rubypants","version":"0.2.0","platform":"ruby","checksum":"f07e38eac793655a0323fe91946081052341b9e69807026fcf102346589eedee"},
{"name":"rubyzip","version":"2.3.2","platform":"ruby","checksum":"3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f"},
@@ -542,7 +542,7 @@
{"name":"sentry-sidekiq","version":"5.1.1","platform":"ruby","checksum":"e4c3618577fba37f7a9fc3812013a7868d09e0e0a0970efc605e6e184079d1af"},
{"name":"set","version":"1.0.1","platform":"ruby","checksum":"d169fe8df4738e9da1118199429a9cf1ce0ac5e8a3cacc481e2ed24d585419dd"},
{"name":"settingslogic","version":"2.0.9","platform":"ruby","checksum":"5925a91d0d48dfb59a6e48ae2bb9c9b801fe6fab25a8e8d302ce8699d92f2ae6"},
-{"name":"sexp_processor","version":"4.15.1","platform":"ruby","checksum":"9291a0f2247f50d15068ee6965b67cd7b678b0d273e18adf3c0b2ea4a890125c"},
+{"name":"sexp_processor","version":"4.16.1","platform":"ruby","checksum":"5caadbf4bbe5ab539cb892a5bcf74ca33a2f2a897cecafdee4a63be79b4819dc"},
{"name":"shellany","version":"0.0.1","platform":"ruby","checksum":"0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7"},
{"name":"shoulda-matchers","version":"5.1.0","platform":"ruby","checksum":"a01d20589989e9653ab4a28c67d9db2b82bcf0a2496cf01d5e1a95a4aaaf5b07"},
{"name":"sidekiq","version":"6.5.7","platform":"ruby","checksum":"7d966fd84d42a942615d6874be31e40f8bece841fdd9b96fc53cad22a590555c"},
@@ -604,7 +604,7 @@
{"name":"truncato","version":"0.7.12","platform":"ruby","checksum":"fed9e8a04fa35fd1a64506cd2089761bae4adfe47e756c3ce98a5c43856c9c4c"},
{"name":"tty-color","version":"0.6.0","platform":"ruby","checksum":"6f9c37ca3a4e2367fb2e6d09722762647d6f455c111f05b59f35730eeb24332a"},
{"name":"tty-cursor","version":"0.7.1","platform":"ruby","checksum":"79534185e6a777888d88628b14b6a1fdf5154a603f285f80b1753e1908e0bf48"},
-{"name":"tty-markdown","version":"0.7.0","platform":"ruby","checksum":"251e8ef71f6a8bc91faa48aa49c341aff644321f493f94c030e571c5aa59e642"},
+{"name":"tty-markdown","version":"0.7.1","platform":"ruby","checksum":"062face5613adc2ec3d500e4c06e6b090699a97cad62d9dfa55d645f60ebdc92"},
{"name":"tty-prompt","version":"0.23.1","platform":"ruby","checksum":"fcdbce905238993f27eecfdf67597a636bc839d92192f6a0eef22b8166449ec8"},
{"name":"tty-reader","version":"0.9.0","platform":"ruby","checksum":"c62972c985c0b1566f0e56743b6a7882f979d3dc32ff491ed490a076f899c2b1"},
{"name":"tty-screen","version":"0.8.1","platform":"ruby","checksum":"6508657c38f32bdca64880abe201ce237d80c94146e1f9b911cba3c7823659a2"},
diff --git a/Gemfile.lock b/Gemfile.lock
index f7e021aae7e..9a6ce249d97 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -974,7 +974,7 @@ GEM
train-core
wmi-lite (~> 1.0)
oj (3.13.23)
- oj-introspect (0.7.1)
+ oj-introspect (0.7.2)
oj (>= 3.13.23)
omniauth (2.1.0)
hashie (>= 3.4.6)
@@ -1102,8 +1102,8 @@ GEM
pry (~> 0.13.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
- pry-shell (0.5.1)
- pry (~> 0.13.0)
+ pry-shell (0.6.0)
+ pry (>= 0.13.0)
tty-markdown
tty-prompt
public_suffix (5.0.0)
@@ -1301,8 +1301,8 @@ GEM
rexml
ruby-statistics (3.0.0)
ruby2_keywords (0.0.5)
- ruby_parser (3.15.0)
- sexp_processor (~> 4.9)
+ ruby_parser (3.19.2)
+ sexp_processor (~> 4.16)
rubyntlm (0.6.3)
rubypants (0.2.0)
rubyzip (2.3.2)
@@ -1352,7 +1352,7 @@ GEM
sidekiq (>= 3.0)
set (1.0.1)
settingslogic (2.0.9)
- sexp_processor (4.15.1)
+ sexp_processor (4.16.1)
shellany (0.0.1)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
@@ -1481,7 +1481,7 @@ GEM
nokogiri (>= 1.7.0, <= 2.0)
tty-color (0.6.0)
tty-cursor (0.7.1)
- tty-markdown (0.7.0)
+ tty-markdown (0.7.1)
kramdown (>= 1.16.2, < 3.0)
pastel (~> 0.8)
rouge (~> 3.14)
@@ -1783,7 +1783,7 @@ DEPENDENCIES
prometheus-client-mmap (~> 0.17)
pry-byebug
pry-rails (~> 0.3.9)
- pry-shell (~> 0.5.1)
+ pry-shell (~> 0.6.0)
puma (~> 5.6.5)
puma_worker_killer (~> 0.3.1)
rack (~> 2.2.6, >= 2.2.6.2)
@@ -1820,7 +1820,7 @@ DEPENDENCIES
ruby-magic (~> 0.5)
ruby-progressbar (~> 1.10)
ruby-saml (~> 1.13.0)
- ruby_parser (~> 3.15)
+ ruby_parser (~> 3.19)
rubyzip (~> 2.3.2)
rugged (~> 1.2)
sanitize (~> 6.0)
diff --git a/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue b/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue
index e359344ab77..ebcda4f0ac3 100644
--- a/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue
@@ -37,10 +37,10 @@ export default {
return job.detailedStatus?.detailsPath;
},
projectName(job) {
- return job.pipeline?.project?.name;
+ return job.project?.name;
},
projectWebUrl(job) {
- return job.pipeline?.project?.webUrl;
+ return job.project?.webUrl;
},
commitShortSha(job) {
return job.shortSha;
diff --git a/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql
index 075dbb06190..b6d6996a857 100644
--- a/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql
@@ -15,13 +15,10 @@ query getRunnerJobs($id: CiRunnerID!, $first: Int, $last: Int, $before: String,
icon
text
}
- pipeline {
+ project {
id
- project {
- id
- name
- webUrl
- }
+ name
+ webUrl
}
shortSha
commitPath
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_item.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_item.vue
index b026e2d57e2..89a565e280d 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_item.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_item.vue
@@ -32,10 +32,10 @@ export default {
type: String,
required: true,
},
- eventTag: {
- type: String,
+ eventTags: {
+ type: Array,
required: false,
- default: null,
+ default: () => [],
},
},
computed: {
@@ -56,16 +56,19 @@ export default {
<gl-icon :name="getEventIcon(action)" class="note-icon" />
</div>
<div class="timeline-event-note timeline-event-border" data-testid="event-text-container">
- <div class="gl-display-flex gl-align-items-center gl-mb-3">
- <h3 class="gl-font-weight-bold gl-font-sm gl-my-0" data-testid="event-time">
+ <div class="gl-display-flex gl-flex-wrap gl-align-items-center gl-gap-3 gl-mb-3">
+ <h3
+ class="timeline-event-note-date gl-font-weight-bold gl-font-sm gl-my-0"
+ data-testid="event-time"
+ >
<gl-sprintf :message="$options.i18n.timeUTC">
<template #time>
<span class="gl-font-lg">{{ time }}</span>
</template>
</gl-sprintf>
</h3>
- <gl-badge v-if="eventTag" variant="muted" icon="tag" class="gl-ml-3">
- {{ eventTag }}
+ <gl-badge v-for="tag in eventTags" :key="tag.key" variant="muted" icon="tag">
+ {{ tag.name }}
</gl-badge>
</div>
<div v-safe-html="noteHtml" class="md"></div>
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
index 8540ffdc063..84bddb45ffa 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
@@ -50,9 +50,6 @@ export default {
},
},
methods: {
- getFirstTag(eventTag) {
- return eventTag.nodes?.[0]?.name;
- },
handleEditSelection(event) {
this.eventToEdit = event.id;
this.$emit('hide-new-incident-timeline-event-form');
@@ -169,7 +166,7 @@ export default {
:action="event.action"
:occurred-at="event.occurredAt"
:note-html="event.noteHtml"
- :event-tag="getFirstTag(event.timelineEventTags)"
+ :event-tags="event.timelineEventTags.nodes"
@delete="handleDelete(event)"
@edit="handleEditSelection(event)"
/>
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index 46704d96552..667fd89af55 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -16,6 +16,7 @@ import syntaxHighlight from '~/syntax_highlight';
import ZenMode from '~/zen_mode';
import '~/sourcegraph/load';
import DiffStats from '~/diffs/components/diff_stats.vue';
+import { initReportAbuse } from '~/projects/report_abuse';
const hasPerfBar = document.querySelector('.with-performance-bar');
const performanceHeight = hasPerfBar ? 35 : 0;
@@ -26,6 +27,7 @@ new ShortcutsNavigation();
initCommitBoxInfo();
initDeprecatedNotes();
+initReportAbuse();
const loadDiffStats = () => {
const diffStatsElements = document.querySelectorAll('#js-diff-stats');
@@ -67,6 +69,7 @@ if (filesContainer.length) {
handleLocationHash();
new Diff();
loadDiffStats();
+ initReportAbuse();
})
.catch(() => {
createAlert({ message: __('An error occurred while retrieving diff files') });
diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
index f0a955e5360..91394755367 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/show/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
@@ -1,5 +1,5 @@
import initNotesApp from '~/mr_notes/init_notes';
-import { initReportAbuse } from '~/projects/merge_requests';
+import { initReportAbuse } from '~/projects/report_abuse';
import { initMrPage } from '../page';
initMrPage();
diff --git a/app/assets/javascripts/projects/commit/store/getters.js b/app/assets/javascripts/projects/commit/store/getters.js
index e0c36df8a75..b039ee3ba63 100644
--- a/app/assets/javascripts/projects/commit/store/getters.js
+++ b/app/assets/javascripts/projects/commit/store/getters.js
@@ -1,7 +1,7 @@
-import { uniq } from 'lodash';
+import { uniq, uniqBy } from 'lodash';
export const joinedBranches = (state) => {
return uniq(state.branches).sort();
};
-export const sortedProjects = (state) => uniq(state.projects).sort();
+export const sortedProjects = (state) => uniqBy(state.projects, 'id').sort();
diff --git a/app/assets/javascripts/projects/merge_requests/index.js b/app/assets/javascripts/projects/merge_requests/index.js
deleted file mode 100644
index fd85a8d0dba..00000000000
--- a/app/assets/javascripts/projects/merge_requests/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import Vue from 'vue';
-import ReportAbuseDropdownItem from './components/report_abuse_dropdown_item.vue';
-
-export const initReportAbuse = () => {
- const el = document.getElementById('js-report-abuse-dropdown-item');
-
- if (!el) return false;
-
- const { reportAbusePath, reportedUserId, reportedFromUrl } = el.dataset;
-
- return new Vue({
- el,
- name: 'ReportAbuseDropdownItemRoot',
- provide: {
- reportAbusePath,
- reportedUserId: parseInt(reportedUserId, 10),
- reportedFromUrl,
- },
- render(createElement) {
- return createElement(ReportAbuseDropdownItem);
- },
- });
-};
diff --git a/app/assets/javascripts/projects/merge_requests/components/report_abuse_dropdown_item.vue b/app/assets/javascripts/projects/report_abuse/components/report_abuse_dropdown_item.vue
index ff76ca7c862..ff76ca7c862 100644
--- a/app/assets/javascripts/projects/merge_requests/components/report_abuse_dropdown_item.vue
+++ b/app/assets/javascripts/projects/report_abuse/components/report_abuse_dropdown_item.vue
diff --git a/app/assets/javascripts/projects/report_abuse/index.js b/app/assets/javascripts/projects/report_abuse/index.js
new file mode 100644
index 00000000000..9bcfdbf6165
--- /dev/null
+++ b/app/assets/javascripts/projects/report_abuse/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import ReportAbuseDropdownItem from './components/report_abuse_dropdown_item.vue';
+
+export const initReportAbuse = () => {
+ const items = document.querySelectorAll('.js-report-abuse-dropdown-item');
+
+ items.forEach((el) => {
+ if (!el) return false;
+
+ const { reportAbusePath, reportedUserId, reportedFromUrl } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'ReportAbuseDropdownItemRoot',
+ provide: {
+ reportAbusePath,
+ reportedUserId: parseInt(reportedUserId, 10),
+ reportedFromUrl,
+ },
+ render(createElement) {
+ return createElement(ReportAbuseDropdownItem);
+ },
+ });
+ });
+};
diff --git a/app/assets/javascripts/releases/components/release_block_assets.vue b/app/assets/javascripts/releases/components/release_block_assets.vue
index 1761f4360d1..cc28980a6bf 100644
--- a/app/assets/javascripts/releases/components/release_block_assets.vue
+++ b/app/assets/javascripts/releases/components/release_block_assets.vue
@@ -121,7 +121,7 @@ export default {
<gl-icon :name="section.iconName" class="gl-mr-2 gl-flex-shrink-0 gl-flex-grow-0" />
{{ link.name }}
<gl-icon
- v-if="link.external"
+ v-if="section.title"
v-gl-tooltip
name="external-link"
:aria-label="$options.externalLinkTooltipText"
diff --git a/app/assets/javascripts/snippet/snippet_show.js b/app/assets/javascripts/snippet/snippet_show.js
index 6d0e4770e1c..277d43e43a4 100644
--- a/app/assets/javascripts/snippet/snippet_show.js
+++ b/app/assets/javascripts/snippet/snippet_show.js
@@ -3,11 +3,13 @@ import initDeprecatedNotes from '~/init_deprecated_notes';
import SnippetsAppFactory from '~/snippets';
import SnippetsShow from '~/snippets/components/show.vue';
import ZenMode from '~/zen_mode';
+import { initReportAbuse } from '~/projects/report_abuse';
SnippetsAppFactory(document.getElementById('js-snippet-view'), SnippetsShow);
initDeprecatedNotes();
loadAwardsHandler();
+initReportAbuse();
// eslint-disable-next-line no-new
new ZenMode();
diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue b/app/assets/javascripts/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue
index f0b20adc5cf..6155a912683 100644
--- a/app/assets/javascripts/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue
@@ -70,6 +70,9 @@ export default {
artifacts() {
return this.reportArtifacts || [];
},
+ hasSecurityReports() {
+ return this.artifacts.length > 0;
+ },
},
methods: {
handleIsLoading(value) {
@@ -99,6 +102,7 @@ export default {
<template>
<mr-widget
+ v-if="hasSecurityReports"
:has-error="hasError"
:error-text="$options.i18n.apiError"
:status-icon-name="$options.icons.warning"
@@ -108,7 +112,7 @@ export default {
:summary="$options.i18n.scansHaveRun"
@is-loading="handleIsLoading"
>
- <template v-if="artifacts.length > 0" #action-buttons>
+ <template #action-buttons>
<div class="gl-ml-3">
<gl-dropdown
v-gl-tooltip
diff --git a/app/assets/stylesheets/page_bundles/incidents.scss b/app/assets/stylesheets/page_bundles/incidents.scss
index f9d0038f970..99e84777c44 100644
--- a/app/assets/stylesheets/page_bundles/incidents.scss
+++ b/app/assets/stylesheets/page_bundles/incidents.scss
@@ -72,3 +72,9 @@
.timeline-event-note .md p {
@include gl-text-gray-700;
}
+
+.timeline-event-note-date {
+ @media (max-width: $breakpoint-md) {
+ width: 100%;
+ }
+}
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 7ae7d126414..cec506405b7 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -152,7 +152,7 @@ module IssuablesHelper
end
if issuable.is_a?(Issue) && issuable.service_desk_reply_to
- output << "#{html_escape(issuable.service_desk_reply_to)} via "
+ output << "#{html_escape(issuable.present(current_user: current_user).service_desk_reply_to)} via "
end
output << content_tag(:strong) do
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index 56138ba95c2..8251e1cba8a 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -45,10 +45,7 @@ module SessionsHelper
end
def obfuscated_email(email)
- regex = ::Gitlab::UntrustedRegexp.new('^(..?)(.*)(@.?)(.*)(\..*)$')
- match = regex.match(email)
- return email unless match
-
- match[1] + '*' * (match[2] || '').length + match[3] + '*' * (match[4] || '').length + match[5]
+ # Moved to Gitlab::Utils::Email in 15.9
+ Gitlab::Utils::Email.obfuscated_email(email)
end
end
diff --git a/app/models/issue_email_participant.rb b/app/models/issue_email_participant.rb
index dd963bc9e7e..9d7e2afa1d9 100644
--- a/app/models/issue_email_participant.rb
+++ b/app/models/issue_email_participant.rb
@@ -2,6 +2,7 @@
class IssueEmailParticipant < ApplicationRecord
include BulkInsertSafe
+ include Presentable
belongs_to :issue
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 3fe84b42739..053989d8eb1 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -35,8 +35,6 @@ class Namespace < ApplicationRecord
SHARED_RUNNERS_SETTINGS = [SR_DISABLED_AND_UNOVERRIDABLE, SR_DISABLED_WITH_OVERRIDE, SR_DISABLED_AND_OVERRIDABLE, SR_ENABLED].freeze
URL_MAX_LENGTH = 255
- PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
-
# This date is just a placeholder until namespace storage enforcement timeline is confirmed at which point
# this should be replaced, see https://about.gitlab.com/pricing/faq-efficient-free-tier/#user-limits-on-gitlab-saas-free-tier
MIN_STORAGE_ENFORCEMENT_DATE = 3.months.from_now.to_date
@@ -242,27 +240,9 @@ class Namespace < ApplicationRecord
end
def clean_path(path, limited_to: Namespace.all)
- path = path.dup
- # Get the email username by removing everything after an `@` sign.
- path.gsub!(/@.*\z/, "")
- # Remove everything that's not in the list of allowed characters.
- path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
- # Remove trailing violations ('.atom', '.git', or '.')
- loop do
- orig = path
- PATH_TRAILING_VIOLATIONS.each { |ext| path = path.chomp(ext) }
- break if orig == path
- end
-
- # Remove leading violations ('-')
- path.gsub!(/\A\-+/, "")
-
- # Users with the great usernames of "." or ".." would end up with a blank username.
- # Work around that by setting their username to "blank", followed by a counter.
- path = "blank" if path.blank?
-
- uniquify = Uniquify.new
- uniquify.string(path) { |s| limited_to.find_by_path_or_name(s) }
+ slug = Gitlab::Slug::Path.new(path).generate
+ path = Namespaces::RandomizedSuffixPath.new(slug)
+ Uniquify.new.string(path) { |s| limited_to.find_by_path_or_name(s) }
end
def clean_name(value)
diff --git a/app/models/namespaces/randomized_suffix_path.rb b/app/models/namespaces/randomized_suffix_path.rb
new file mode 100644
index 00000000000..586d7bff5c3
--- /dev/null
+++ b/app/models/namespaces/randomized_suffix_path.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class RandomizedSuffixPath
+ MAX_TRIES = 4
+ LEADING_ZEROS = /^0+/.freeze
+
+ def initialize(path)
+ @path = path
+ end
+
+ def call(new_count)
+ @count = new_count.to_i
+ to_s
+ end
+
+ def to_s
+ "#{path}#{suffix}"
+ end
+
+ private
+
+ attr_reader :count, :path
+
+ def randomized_suffix
+ Time.current.strftime('%L%M%V').sub(LEADING_ZEROS, '').to_i + offset
+ end
+
+ def offset
+ count - MAX_TRIES - 1
+ end
+
+ def suffix
+ return if count.nil?
+ return randomized_suffix if count > MAX_TRIES
+ return count if count > 0
+ end
+ end
+end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 228ebf1d665..e939a4eb56b 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -189,9 +189,7 @@ class Repository
return []
end
- query = Feature.enabled?(:commit_search_trailing_spaces) ? query.strip : query
-
- commits = raw_repository.find_commits_by_message(query, ref, path, limit, offset).map do |c|
+ commits = raw_repository.find_commits_by_message(query.strip, ref, path, limit, offset).map do |c|
commit(c)
end
CommitCollection.new(container, commits, ref)
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index b85a57f81cd..34c5be7d972 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -344,6 +344,7 @@ class ProjectPolicy < BasePolicy
enable :read_package
enable :read_product_analytics
enable :read_ci_cd_analytics
+ enable :read_external_emails
enable :read_grafana
end
diff --git a/app/presenters/issue_email_participant_presenter.rb b/app/presenters/issue_email_participant_presenter.rb
new file mode 100644
index 00000000000..8688b9a2af1
--- /dev/null
+++ b/app/presenters/issue_email_participant_presenter.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class IssueEmailParticipantPresenter < Gitlab::View::Presenter::Delegated
+ presents ::IssueEmailParticipant, as: :participant
+
+ delegator_override :email
+ def email
+ return super if Ability.allowed?(current_user, :read_external_emails, participant.issue.project)
+
+ Gitlab::Utils::Email.obfuscated_email(super, deform: true)
+ end
+end
diff --git a/app/presenters/issue_presenter.rb b/app/presenters/issue_presenter.rb
index 9b4e7e22165..69d775d8125 100644
--- a/app/presenters/issue_presenter.rb
+++ b/app/presenters/issue_presenter.rb
@@ -15,6 +15,19 @@ class IssuePresenter < Gitlab::View::Presenter::Delegated
def project_emails_disabled?
issue.project.emails_disabled?
end
+
+ delegator_override :service_desk_reply_to
+ def service_desk_reply_to
+ return unless super.present?
+ return super if Ability.allowed?(current_user, :read_external_emails, issue.project)
+
+ Gitlab::Utils::Email.obfuscated_email(super, deform: true)
+ end
+
+ delegator_override :issue_email_participants
+ def issue_email_participants
+ issue.issue_email_participants.present(current_user: current_user)
+ end
end
IssuePresenter.prepend_mod_with('IssuePresenter')
diff --git a/app/serializers/issue_entity.rb b/app/serializers/issue_entity.rb
index a38f345f617..340fd8803af 100644
--- a/app/serializers/issue_entity.rb
+++ b/app/serializers/issue_entity.rb
@@ -89,12 +89,13 @@ class IssueEntity < IssuableEntity
end
expose :issue_email_participants do |issue|
- # TODO - This is a Temporary solution to avoid leaking participants' emails
- # on public/internal projects when issue is not confidential.
- # Should be removed when https://gitlab.com/gitlab-org/gitlab/-/issues/383448 is implemented.
- next [] unless issue.confidential?
+ presented_issue = issue.present(current_user: request.current_user)
- issue.issue_email_participants.map { |x| { email: x.email } }
+ presented_issue.issue_email_participants.map do |participant|
+ {
+ email: participant.email
+ }
+ end
end
expose :issue_type,
diff --git a/app/serializers/note_entity.rb b/app/serializers/note_entity.rb
index 58ad5812801..679f829e852 100644
--- a/app/serializers/note_entity.rb
+++ b/app/serializers/note_entity.rb
@@ -66,8 +66,8 @@ class NoteEntity < API::Entities::Note
expose :emoji_awardable?, as: :emoji_awardable
expose :award_emoji, if: -> (note, _) { note.emoji_awardable? }, using: AwardEmojiEntity
- expose :report_abuse_path, if: -> (note, _) { note.author_id } do |note|
- new_abuse_report_path(user_id: note.author_id, ref_url: Gitlab::UrlBuilder.build(note))
+ expose :report_abuse_path do |note| # @deprecated To be removed in API version 5
+ add_category_abuse_reports_path
end
expose :noteable_note_url do |note|
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 1d3320e4f82..18975bc3db6 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -20,7 +20,7 @@
%span.issuable-authored.d-none.d-sm-inline-block
&middot;
- if issue.service_desk_reply_to
- #{_('created %{timeAgoString} by %{email} via %{user}').html_safe % { timeAgoString: time_ago_with_tooltip(issue.created_at, placement: 'bottom'), email: issue.service_desk_reply_to, user: link_to_member(@project, issue.author, avatar: false) }}
+ #{_('created %{timeAgoString} by %{email} via %{user}').html_safe % { timeAgoString: time_ago_with_tooltip(issue.created_at, placement: 'bottom'), email: issue.present(current_user: current_user).service_desk_reply_to, user: link_to_member(@project, issue.author, avatar: false) }}
- else
#{s_('IssueList|created %{timeAgoString} by %{user}').html_safe % { timeAgoString: time_ago_with_tooltip(issue.created_at, placement: 'bottom'), user: link_to_member(@project, issue.author, avatar: false) }}
= render_if_exists 'shared/issuable/gitlab_team_member_badge', author: issue.author
diff --git a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
index 0123c5efd3d..92b0a5a0b90 100644
--- a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
+++ b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
@@ -47,6 +47,6 @@
- if moved_mr_sidebar_enabled?
%li.gl-dropdown-divider
%hr.dropdown-divider
- #js-report-abuse-dropdown-item{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @merge_request.author.id, reported_from_url: merge_request_url(@merge_request) } }
+ .js-report-abuse-dropdown-item{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @merge_request.author.id, reported_from_url: merge_request_url(@merge_request) } }
#js-report-abuse-drawer
diff --git a/app/views/projects/notes/_more_actions_dropdown.html.haml b/app/views/projects/notes/_more_actions_dropdown.html.haml
index 2351bd209a7..8c94a18e1b0 100644
--- a/app/views/projects/notes/_more_actions_dropdown.html.haml
+++ b/app/views/projects/notes/_more_actions_dropdown.html.haml
@@ -8,9 +8,8 @@
%li
= clipboard_button(text: noteable_note_url(note), title: _('Copy reference'), button_text: _('Copy link'), class: 'btn-clipboard', hide_tooltip: true, hide_button_icon: true)
- unless is_current_user
- %li
- = link_to new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) do
- = _('Report abuse to administrator')
+ .gl-ml-n2
+ .js-report-abuse-dropdown-item{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: note.author.id, reported_from_url: noteable_note_url(note) } }
- if note_editable
%li
= link_to note_url(note), method: :delete, data: { confirm: _('Are you sure you want to delete this comment?'), confirm_btn_variant: 'danger', qa_selector: 'delete_comment_button' }, aria: { label: _('Delete comment') }, remote: true, class: 'js-note-delete' do
diff --git a/app/views/shared/notes/_notes_with_form.html.haml b/app/views/shared/notes/_notes_with_form.html.haml
index e34f412baa4..eb36de8167c 100644
--- a/app/views/shared/notes/_notes_with_form.html.haml
+++ b/app/views/shared/notes/_notes_with_form.html.haml
@@ -27,3 +27,5 @@
= html_escape(_("This %{issuable} is locked. Only %{strong_open}project members%{strong_close} can comment.")) % { issuable: issuable.class.to_s.titleize.downcase, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
-# haml-lint:disable InlineJavaScript
%script.js-notes-data{ type: "application/json" }= initial_notes_data(autocomplete).to_json.html_safe
+
+#js-report-abuse-drawer
diff --git a/config/feature_flags/development/commit_search_trailing_spaces.yml b/config/feature_flags/development/commit_search_trailing_spaces.yml
deleted file mode 100644
index b4d2f911620..00000000000
--- a/config/feature_flags/development/commit_search_trailing_spaces.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: commit_search_trailing_spaces
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107956
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/386825
-milestone: '15.8'
-type: development
-group: group::source code
-default_enabled: true
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 43d13b8ea32..0c7bd33c2c1 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -13,12 +13,13 @@ to support user authentication.
This integration works with most LDAP-compliant directory servers, including:
- Microsoft Active Directory.
- [Microsoft Active Directory Trusts](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc771568(v=ws.10))
- are not supported.
- Apple Open Directory.
- Open LDAP.
- 389 Server.
+NOTE:
+GitLab does not support [Microsoft Active Directory Trusts](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc771568(v=ws.10)).
+
Users added through LDAP:
- Usually use a [licensed seat](../../../subscriptions/self_managed/index.md#billable-users).
diff --git a/doc/development/application_slis/rails_request_apdex.md b/doc/development/application_slis/rails_request_apdex.md
index ae53ddc1c00..19a9c67eb8e 100644
--- a/doc/development/application_slis/rails_request_apdex.md
+++ b/doc/development/application_slis/rails_request_apdex.md
@@ -228,6 +228,9 @@ get 'client/features', urgency: :low do
end
```
+WARNING:
+We can't specify the urgency at the namespace level. The directive is ignored when doing so.
+
### Error budget attribution and ownership
This SLI is used for service level monitoring. It feeds into the
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 4eb5bedef1c..707ec6d1b71 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -139,8 +139,8 @@ To do so:
### Simulate a SaaS instance
-If you're developing locally and need your instance to simulate the SaaS (GitLab.com)
-version of the product:
+If you run GitLab in development or have a license installed issued to a `@gitlab.com` email
+and you need your instance to simulate the SaaS (GitLab.com) version of the product:
1. Export this environment variable:
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index e7e628f5293..508219cee43 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -134,7 +134,7 @@ lint:
Including a `.golangci.yml` in the root directory of the project allows for
configuration of `golangci-lint`. All options for `golangci-lint` are listed in
-this [example](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml).
+this [example](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml).
Once [recursive includes](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/56836)
become available, you can share job templates like this
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index ac73e6e794c..69d3a125ae6 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -223,7 +223,7 @@ The following Elasticsearch settings are available:
| `AWS Secret Access Key` | The AWS secret access key. |
| `Maximum file size indexed` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-file-size-indexed). |
| `Maximum field length` | See [the explanation in instance limits.](../../administration/instance_limits.md#maximum-field-length). |
-| `Maximum bulk request size (MiB)` | The Maximum Bulk Request size is used by the GitLab Golang-based indexer processes and indicates how much data it ought to collect (and store in memory) in a given indexing process before submitting the payload to Elasticsearch's Bulk API. This setting should be used with the Bulk request concurrency setting (see below) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
+| `Maximum bulk request size (MiB)` | Used by the GitLab Ruby and Golang-based indexer processes. This setting indicates how much data must be collected (and stored in memory) in a given indexing process before submitting the payload to the Elasticsearch Bulk API. For the GitLab Golang-based indexer, you should use this setting with `Bulk request concurrency`. `Maximum bulk request size (MiB)` must accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer from either the `gitlab-rake` command or the Sidekiq tasks. |
| `Bulk request concurrency` | The Bulk request concurrency indicates how many of the GitLab Golang-based indexer processes (or threads) can run in parallel to collect data to subsequently submit to the Elasticsearch Bulk API. This increases indexing performance, but fills the Elasticsearch bulk requests queue faster. This setting should be used together with the Maximum bulk request size setting (see above) and needs to accommodate the resource constraints of both the Elasticsearch hosts and the hosts running the GitLab Golang-based indexer either from the `gitlab-rake` command or the Sidekiq tasks. |
| `Client request timeout` | Elasticsearch HTTP client request timeout value in seconds. `0` means using the system default timeout value, which depends on the libraries that GitLab application is built upon. |
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
index fdcfbe0cb2c..806e275489f 100644
--- a/doc/operations/incident_management/integrations.md
+++ b/doc/operations/incident_management/integrations.md
@@ -9,8 +9,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13203) in GitLab 12.4.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42640) from GitLab Ultimate to GitLab Free in 12.8.
-GitLab can accept alerts from any source via a webhook receiver. This can be configured
-generically.
+GitLab can accept alerts from any source via a webhook receiver. [Alert notifications](alerts.md)
+can [trigger paging](paging.md#paging) for on-call rotations or be used to [create incidents](manage_incidents.md#from-an-alert).
## Integrations list
@@ -138,6 +138,175 @@ Example payload:
}
```
+### Prometheus endpoint
+
+Prerequisites:
+
+- You must have at least the Maintainer role for the project.
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Monitor**.
+1. Expand the **Alerts** section, and select **Add new integration**.
+1. From the **Select integration type** dropdown list, select **Prometheus**.
+1. Turn on the **Active** toggle.
+1. Enter the **Prometheus API base URL**.
+ You should enter a placeholder URL. The features which use this field are [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346541) and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/379252) in GitLab 16.0.
+1. Select **Save integration**.
+
+The URL and authorization key for the webhook configuration
+are available in the **View credentials** tab.
+
+Enter the URL and authorization key in your external service.
+You can also send a test alert from your integration's
+[**Send test alert**](#triggering-test-alerts) tab.
+
+#### Add integration credentials to Prometheus Alertmanager
+
+To send Prometheus alert notifications to GitLab, copy the URL and authorization key from
+your [Prometheus integration](#prometheus-endpoint) into the
+[`webhook_configs`](https://prometheus.io/docs/alerting/latest/configuration/#webhook_config)
+section of the Prometheus Alertmanager configuration:
+
+```yaml
+receivers:
+ - name: gitlab
+ webhook_configs:
+ - http_config:
+ authorization:
+ type: Bearer
+ credentials: 1234567890abdcdefg
+ send_resolved: true
+ url: http://IP_ADDRESS:PORT/root/manual_prometheus/prometheus/alerts/notify.json
+ # Rest of configuration omitted
+ # ...
+```
+
+#### Expected request attributes
+
+Alerts are expected to be formatted for a Prometheus [webhook receiver](https://prometheus.io/docs/alerting/latest/configuration/#webhook_config).
+
+Top-level required attributes:
+
+- `alerts`
+- `commonAnnotations`
+- `commonLabels`
+- `externalURL`
+- `groupKey`
+- `groupLabels`
+- `receiver`
+- `status`
+- `version`
+
+From `alerts` in the Prometheus payload, a GitLab alert is created for each item in the array.
+You can alter the nested parameters listed below to configure the GitLab alert.
+
+| Attribute | Type | Required | Description |
+| -------------------------------------------------------------------------- | -------- | -------- | ------------------------------------ |
+| One of `annotations/title`, `annotations/summary`, or `labels/alertname` | String | Yes | The title of the alert. |
+| `startsAt` | DateTime | Yes | The start time of the alert. |
+| `annotations/description` | String | No | A high-level summary of the problem. |
+| `annotations/gitlab_incident_markdown` | String | No | [GitLab Flavored Markdown](../../user/markdown.md) to be appended to any incident created from the alert. |
+| `annotations/runbook` | String | No | Link to documentation or instructions for how to manage this alert. |
+| `endsAt` | DateTime | No | The resolution time of the alert. |
+| `g0.expr` query parameter in `generatorUrl` | String | No | Query of associated metric. |
+| `labels/gitlab_environment_name` | String | No | The name of the associated GitLab [environment](../../ci/environments/index.md). Required to [display alerts on a dashboard](../../user/operations_dashboard/index.md#adding-a-project-to-the-dashboard). |
+| `labels/severity` | String | No | Severity of the alert. Should be one of the [Prometheus severity options](#prometheus-severity-options). Defaults to `critical` if missing or value is not in this list. |
+| `status` | String | No | Status of the alert in Prometheus. If value is 'resolved', the alert is resolved. |
+| One of `annotations/gitlab_y_label`, `annotations/title`, `annotations/summary`, or `labels/alertname` | String | No | The Y-Axis label to be used when embedding the metrics for this alert in [GitLab Flavored Markdown](../../user/markdown.md). |
+
+Additional attributes included under `annotations` are available on
+the [alert details page](alerts.md#alert-details-page). Any other attributes are ignored.
+
+Attributes aren't limited to primitive types (such as strings or numbers), but
+can be a nested JSON object. For example:
+
+```json
+{
+ "target": {
+ "user": {
+ "id": 42
+ }
+ }
+}
+```
+
+NOTE:
+Ensure your requests are smaller than the
+[payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
+
+#### Prometheus severity options
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50871) in GitLab 13.9
+
+Alerts from Prometheus can provide any of the case-insensitive follow values for [alert severity](../incident_management/alerts.md#alert-severity):
+
+- **Critical**: `critical`, `s1`, `p1`, `emergency`, `fatal`
+- **High**: `high`, `s2`, `p2`, `major`, `page`
+- **Medium**: `medium`, `s3`, `p3`, `error`, `alert`
+- **Low**: `low`, `s4`, `p4`, `warn`, `warning`
+- **Info**: `info`, `s5`, `p5`, `debug`, `information`, `notice`
+
+The severity defaults to `critical` if the value is missing or not in this list.
+
+#### Example Prometheus alert
+
+Example alerting rule:
+
+```yaml
+groups:
+- name: example
+ rules:
+ - alert: ServiceDown
+ expr: up == 0
+ for: 5m
+ labels:
+ severity: high
+ annotations:
+ title: "Example title"
+ runbook: "http://example.com/my-alert-runbook"
+ description: "Service has been down for more than 5 minutes."
+ gitlab_y_label: "y-axis label"
+ foo:
+ bar:
+ baz: 42
+```
+
+Example request payload:
+
+```json
+{
+ "version" : "4",
+ "groupKey": null,
+ "status": "firing",
+ "receiver": "",
+ "groupLabels": {},
+ "commonLabels": {},
+ "commonAnnotations": {},
+ "externalURL": "",
+ "alerts": [{
+ "startsAt": "2022-010-30T11:22:40Z",
+ "generatorURL": "http://host?g0.expr=up",
+ "endsAt": null,
+ "status": "firing",
+ "labels": {
+ "gitlab_environment_name": "production",
+ "severity": "high"
+ },
+ "annotations": {
+ "title": "Example title",
+ "runbook": "http://example.com/my-alert-runbook",
+ "description": "Service has been down for more than 5 minutes.",
+ "gitlab_y_label": "y-axis label",
+ "foo": {
+ "bar": {
+ "baz": 42
+ }
+ }
+ }
+ }]
+}
+```
+
## Authorization
The following authorization methods are accepted:
diff --git a/doc/topics/offline/quick_start_guide.md b/doc/topics/offline/quick_start_guide.md
index 015fd9fc720..2903e072508 100644
--- a/doc/topics/offline/quick_start_guide.md
+++ b/doc/topics/offline/quick_start_guide.md
@@ -12,7 +12,7 @@ instance entirely offline.
## Installation
NOTE:
-This guide assumes the server is Ubuntu 20.04 using the [Omnibus installation method](https://docs.gitlab.com/omnibus/) and will be running GitLab [Enterprise Edition](https://about.gitlab.com/install/ce-or-ee/). Instructions for other servers may vary.
+This guide assumes the server is Ubuntu 20.04 using the [Omnibus installation method](https://docs.gitlab.com/omnibus/) and is running GitLab [Enterprise Edition](https://about.gitlab.com/install/ce-or-ee/). Instructions for other servers may vary.
This guide also assumes the server host resolves as `my-host.internal`, which you should replace with your
server's FQDN, and that you have access to a different server with Internet access to download the required package files.
diff --git a/doc/user/admin_area/credentials_inventory.md b/doc/user/admin_area/credentials_inventory.md
index df53ef0696f..5fee0c42a77 100644
--- a/doc/user/admin_area/credentials_inventory.md
+++ b/doc/user/admin_area/credentials_inventory.md
@@ -54,10 +54,10 @@ When a PAT is revoked from the credentials inventory, the instance notifies the
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/243833) in GitLab 14.8.
-The **Revoke** button next to a project access token can be selected to revoke that particular project access token. This will both:
+The **Revoke** button next to a project access token can be selected to revoke that particular project access token. This both:
-- Revoke the token project access token.
-- Enqueue a background worker to delete the project bot user.
+- Revokes the token project access token.
+- Enqueues a background worker to delete the project bot user.
![Credentials inventory page - Project access tokens](img/credentials_inventory_project_access_tokens_v14_9.png)
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 0410f2589f7..8acded1210d 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -61,19 +61,19 @@ Instance-level protection against accidental deletion of groups and projects.
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/352960) in GitLab 15.1.
-Groups and projects will remain restorable within a defined retention period. By default this is 7 days but it can be changed.
+Groups and projects remain restorable within a defined retention period. By default this is 7 days but it can be changed.
Setting the retention period to `0` means that groups and project are removed immediately and cannot be restored.
In GitLab 15.1 and later, the retention period must be between `1` and `90`. If the retention period was `0` before the 15.1 update,
-then it will get automatically changed to `1` while also disabling deletion protection the next time any application setting is changed.
+then it gets automatically changed to `1` while also disabling deletion protection the next time any application setting is changed.
### Delayed project deletion
> User interface [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/352960) in GitLab 15.1.
Administrators can enable [delayed project deletion](../../project/settings/index.md#delayed-project-deletion) by default for
-newly-created groups. Group owners can choose to disable this and existing groups will retain their existing setting. When enabled
-deleted groups will remain restorable within a retention period.
+newly-created groups. Group owners can choose to disable this. When disabled, existing groups retain their existing setting. When enabled
+deleted groups remain restorable within a retention period.
To configure delayed project deletion:
@@ -95,7 +95,7 @@ In GitLab 15.1, and later this setting is enforced on groups when disabled and i
> User interface [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352960) in GitLab 15.1.
-Groups will remain restorable if the retention period is `1` or more days.
+Groups remain restorable if the retention period is `1` or more days.
In GitLab 15.1 and later, delayed group deletion can be enabled by setting **Deletion projection** to **Keep deleted**.
diff --git a/doc/user/application_security/get-started-security.md b/doc/user/application_security/get-started-security.md
index 5774bf940b0..788100fa57e 100644
--- a/doc/user/application_security/get-started-security.md
+++ b/doc/user/application_security/get-started-security.md
@@ -9,14 +9,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Adopting GitLab application security](https://www.youtube.com/watch?v=5QlxkiKR04k).
-The following steps will help you get the most from GitLab application security tools. These steps are a recommended order of operations. You can choose to implement capabilities in a different order or omit features that do not apply to your specific needs.
+The following steps help you get the most from GitLab application security tools. These steps are a recommended order of operations. You can choose to implement capabilities in a different order or omit features that do not apply to your specific needs.
1. Enable [Secret Detection](secret_detection/index.md) and [Dependency Scanning](dependency_scanning/index.md)
to identify any leaked secrets and vulnerable packages in your codebase.
- For all security scanners, enable them by updating your [`.gitlab-ci.yml`](../../ci/yaml/gitlab_ci_yaml.md) directly on your `default` branch. This creates a baseline scan of your `default` branch, which is necessary for
feature branch scans to be compared against. This allows [merge requests](../project/merge_requests/index.md)
- to display only newly-introduced vulnerabilities. Otherwise, merge requests will display every
+ to display only newly-introduced vulnerabilities. Otherwise, merge requests display every
vulnerability in the branch, regardless of whether it was introduced by a change in the branch.
- If you are after simplicity, enable only Secret Detection first. It only has one analyzer,
no build requirements, and relatively simple findings: is this a secret or not?
@@ -28,7 +28,7 @@ The following steps will help you get the most from GitLab application security
help manage issues created from vulnerabilities. Issue boards allow all stakeholders to have a
common view of all issues and track remediation progress.
1. Use [scheduled pipelines](../../ci/pipelines/schedules.md#scheduled-pipelines) to regularly scan important branches such as `default` or those used for maintenance releases.
- - Running regular dependency and [container scans](container_scanning/index.md) will surface newly-discovered vulnerabilities that already exist in your repository.
+ - Running regular dependency and [container scans](container_scanning/index.md) surface newly-discovered vulnerabilities that already exist in your repository.
- Scheduled scans are most useful for projects or important branches with low development activity where pipeline scans are infrequent.
1. Create a [scan result policy](policies/index.md) to limit new vulnerabilities from being merged
into your `default` branch.
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index 6bf3532f95e..b87c6328d99 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -42,7 +42,7 @@ before the policy changes take effect.
The [policy editor](index.md#policy-editor) supports YAML mode and rule mode.
NOTE:
-Propagating scan result policies created for groups with a large number of projects will take a while to complete.
+Propagating scan result policies created for groups with a large number of projects take a while to complete.
## Scan result policies schema
@@ -110,7 +110,7 @@ the defined policy.
Requirements and limitations:
- You must add the respective [security scanning tools](../index.md#application-coverage).
- Otherwise, scan result policies won't have any effect.
+ Otherwise, scan result policies do not have any effect.
- The maximum number of policies is five.
- Each policy can have a maximum of five rules.
@@ -199,7 +199,7 @@ It corresponds to a single object from the previous example:
## Example situations where scan result policies require additional approval
-There are several situations where the scan result policy will require an additional approval step. For example:
+There are several situations where the scan result policy requires an additional approval step. For example:
- The number of security jobs is reduced in the working branch and no longer matches the number of security jobs in the target branch. Users can't skip the Scanning Result Policies by removing scanning jobs from the CI configuration.
- Someone stops a pipeline security job, and users can't skip the security scan.
diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md
index 6f7fdc46ad4..9edb012ba92 100644
--- a/doc/user/clusters/management_project_template.md
+++ b/doc/user/clusters/management_project_template.md
@@ -75,9 +75,9 @@ The base image used in the pipeline is built by the
This image contains a set of Bash utility scripts to support [Helm v3 releases](https://helm.sh/docs/intro/using_helm/#three-big-concepts).
If you are on a self-managed instance of GitLab, you must modify the `.gitlab-ci.yml` file.
-Specifically, the section that starts with the comment `Automatic package upgrades` will not
+Specifically, the section that starts with the comment `Automatic package upgrades` does not
work on a self-managed instance, because the `include` refers to a GitLab.com project.
-If you remove everything below this comment, the pipeline will succeed.
+If you remove everything below this comment, the pipeline succeeds.
### The main `helmfile.yml` file
diff --git a/doc/user/packages/rubygems_registry/index.md b/doc/user/packages/rubygems_registry/index.md
index 7710ad3db01..ae444880b6b 100644
--- a/doc/user/packages/rubygems_registry/index.md
+++ b/doc/user/packages/rubygems_registry/index.md
@@ -117,7 +117,7 @@ To push your gem, run a command like this one:
gem push my_gem-0.0.1.gem --host <host>
```
-Note that `<host>` is the URL you used when setting up authentication. For example:
+`<host>` is the URL you used when setting up authentication. For example:
```shell
gem push my_gem-0.0.1.gem --host https://gitlab.example.com/api/v4/projects/1/packages/rubygems
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index f178a3254f3..0179ab03dbe 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -368,7 +368,7 @@ The `remember_user_token` lifetime of a cookie can now extend beyond the deadlin
GitLab uses both session and persistent cookies:
-- Session cookie: Session cookies are normally removed at the end of the browser session when
+- Session cookie: Session cookies are typically removed at the end of the browser session when
the browser is closed. The `_gitlab_session` cookie has no fixed expiration date. However,
it expires based on its [`session_expire_delay`](#why-do-you-keep-getting-signed-out).
- Persistent cookie: The `remember_user_token` is a cookie with an expiration date of two weeks.
diff --git a/doc/user/project/code_intelligence.md b/doc/user/project/code_intelligence.md
index d5f9c225cde..3fec38a61a0 100644
--- a/doc/user/project/code_intelligence.md
+++ b/doc/user/project/code_intelligence.md
@@ -43,7 +43,7 @@ code_navigation:
The generated LSIF file size may be limited by
the [artifact application limits (`ci_max_artifact_size_lsif`)](../../administration/instance_limits.md#maximum-file-size-per-type-of-artifact),
-default to 100MB (configurable by an instance administrator).
+default to 100 MB (configurable by an instance administrator).
After the job succeeds, code intelligence data can be viewed while browsing the code:
diff --git a/doc/user/project/highlighting.md b/doc/user/project/highlighting.md
index 22ff234ac81..fbb6d1b329d 100644
--- a/doc/user/project/highlighting.md
+++ b/doc/user/project/highlighting.md
@@ -11,7 +11,7 @@ GitLab provides syntax highlighting on all files through [Highlight.js](https://
[Rouge](https://rubygems.org/gems/rouge) Ruby gem. It attempts to guess what language
to use based on the file extension, which most of the time is sufficient.
-The paths here are Git's built-in [`.gitattributes` interface](https://git-scm.com/docs/gitattributes).
+The paths here use the [`.gitattributes` interface](https://git-scm.com/docs/gitattributes) in Git.
NOTE:
The [Web IDE](web_ide/index.md) and [Snippets](../snippets.md) use [Monaco Editor](https://microsoft.github.io/monaco-editor/)
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index bc133c831e9..7c6e7afb3bc 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -47,7 +47,7 @@ flowchart RL
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9. [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
-Add users to a project so they become members and have permission
+Add users to a project so they become direct members and have permission
to perform actions.
Prerequisite:
@@ -98,13 +98,13 @@ The Owner [role](../../permissions.md#project-members-permissions) can be added
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9. [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
When you add a group to a project, every group member (direct or inherited) gets access to the project.
-Each user's access is based on:
+Each member's access is based on the:
-- The role they're assigned in the group.
-- The maximum role you choose when you invite the group.
+- Role they're assigned in the group.
+- Maximum role you choose when you invite the group.
-If a user has a group role with fewer permissions than the maximum project role, the user keeps the permissions of their group role.
-For example, if you add a user with the Guest role to a project with a maximum role of Maintainer, the user has only the permissions of the Guest role.
+If a group member has a role in the group with fewer permissions than the maximum project role, the member keeps the permissions of their group role.
+For example, if you add a member with the Guest role to a project with a maximum role of Maintainer, the member has only the permissions of the Guest role in the project.
Prerequisites:
@@ -128,10 +128,10 @@ The **Members** tab shows:
- Members who are directly assigned to the project.
- If the project was created in a group [namespace](../../namespace/index.md), members of that group.
-## Import users from another project
+## Import members from another project
-You can import another project's users to your own project. Users
-retain the same permissions as the project you import them from.
+You can import another project's members to your own project.
+Imported project members retain the same permissions as the project you import them from.
Prerequisite:
@@ -171,13 +171,14 @@ If a user is a:
## Remove a member from a project
-If a user is a direct member of a project, you can remove them.
-If membership is inherited from a parent group, then the member can be removed only from the parent
-group itself.
+If a user is:
+
+- A direct member of a project, you can remove them directly from the project.
+- An inherited member from a parent group, you can only remove them from the parent group itself.
Prerequisites:
-- To remove direct members with the:
+- To remove direct members that have the:
- Maintainer, Developer, Reporter, or Guest role, you must have the Maintainer role.
- Owner role, you must have the Owner role.
- Optional. Unassign the member from all issues and merge requests that
@@ -191,7 +192,7 @@ To remove a member from a project:
1. Optional. In the confirmation box, select the
**Also unassign this user from related issues and merge requests** checkbox.
1. To prevent leaks of sensitive information from private projects, verify the
- user has not forked the private repository or created webhooks. Existing forks continue to receive
+ member has not forked the private repository or created webhooks. Existing forks continue to receive
changes from the upstream project, and webhooks continue to receive updates. You may also want to configure your project
to prevent projects in a group
[from being forked outside their group](../../group/access_and_permissions.md#prevent-project-forking-outside-group).
diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md
index a8a79591e9e..cf7d4f44aad 100644
--- a/doc/user/project/repository/reducing_the_repo_size_using_git.md
+++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md
@@ -110,7 +110,7 @@ To purge files from a GitLab repository:
for more examples and the complete documentation.
1. Because you are trying to remove internal refs,
- you'll later rely on `commit-map` files produced by each run
+ you need the `commit-map` files produced by each run
to tell you which internal refs to remove.
Every `git filter-repo` run creates a new `commit-map`,
and overwrites the `commit-map` from the previous run.
@@ -174,7 +174,7 @@ To clean up a repository:
1. Upload a list of objects. For example, a `commit-map` file created by `git filter-repo` which is located in the
`filter-repo` directory.
- If your `commit-map` file is larger than about 250KB or 3000 lines, the file can be split and uploaded piece by piece:
+ If your `commit-map` file is larger than about 250 KB or 3000 lines, the file can be split and uploaded piece by piece:
```shell
split -l 3000 filter-repo/commit-map filter-repo/commit-map-
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index 9d86780e6f4..14f82c7c68c 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -378,10 +378,15 @@ attachments are sent as part of the email. In other cases, the email contains li
#### Privacy considerations
+> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108901) the minimum required role to view the creator's and participant's email in GitLab 15.9.
+
Service Desk issues are confidential, but the project owner can
[make an issue public](issues/confidential_issues.md#modify-issue-confidentiality).
-When a Service Desk issue becomes public, the issue creator's email address is disclosed
-to everyone who can view the project.
+When a Service Desk issue becomes public, the issue creator's and participants' email addresses are
+visible to signed-in users with at least the Reporter role for the project.
+
+In GitLab 15.8 and earlier, when a Service Desk issue becomes public, the issue creator's email
+address is disclosed to everyone who can view the project.
### Support Bot user
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 777d5019a29..5f12275b7a0 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -118,7 +118,7 @@ module API
end
end
- namespace 'kubernetes/agent_configuration', urgency: :low do
+ namespace 'kubernetes/agent_configuration' do
desc 'POST agent configuration' do
detail 'Store configuration for an agent'
end
@@ -126,7 +126,7 @@ module API
requires :agent_id, type: Integer, desc: 'ID of the configured Agent'
requires :agent_config, type: JSON, desc: 'Configuration for the Agent'
end
- post '/', feature_category: :kubernetes_management do
+ post '/', feature_category: :kubernetes_management, urgency: :low do
agent = ::Clusters::Agent.find(params[:agent_id])
::Clusters::Agents::RefreshAuthorizationService.new(agent, config: params[:agent_config]).execute
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index 1190c92ce17..2eff78efbec 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -4,8 +4,11 @@ require 'pathname'
require 'forwardable'
require_relative 'gitlab_edition'
+require_relative 'gitlab/utils'
module Gitlab
+ GITLAB_SIMULATE_SAAS = Gitlab::Utils.to_boolean(ENV['GITLAB_SIMULATE_SAAS'], default: false)
+
class << self
extend Forwardable
@@ -49,10 +52,18 @@ module Gitlab
INSTALLATION_TYPE = File.read(root.join("INSTALLATION_TYPE")).strip.freeze
HTTP_PROXY_ENV_VARS = %w(http_proxy https_proxy HTTP_PROXY HTTPS_PROXY).freeze
+ # We allow GitLab instances to "pretend" they are SaaS to test SaaS-specific code
+ # paths, but only when in development mode or when running on production instances
+ # with a license issued to a GitLab team member.
def self.simulate_com?
- return false unless Rails.env.development?
+ return false unless GITLAB_SIMULATE_SAAS
+ return false if Rails.env.test?
+
+ Rails.env.development? || licensed_to_gitlab_team_member?
+ end
- Gitlab::Utils.to_boolean(ENV['GITLAB_SIMULATE_SAAS'])
+ def self.licensed_to_gitlab_team_member?
+ ee? && ::License.current&.issued_to_gitlab_team_member?
end
def self.com?
diff --git a/lib/gitlab/slug/path.rb b/lib/gitlab/slug/path.rb
new file mode 100644
index 00000000000..434f36829a6
--- /dev/null
+++ b/lib/gitlab/slug/path.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Slug
+ class Path
+ LEADING_DASHES = /\A-+/.freeze
+ # Eextract local email part if given an email. Will remove @ sign and everything following it.
+ EXTRACT_LOCAL_EMAIL_PART = /@.*\z/.freeze
+ FORBIDDEN_CHARACTERS = /[^a-zA-Z0-9_\-.]/.freeze
+ PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
+ DEFAULT_SLUG = 'blank'
+
+ def initialize(input)
+ @input = input.dup.to_s
+ end
+
+ def generate
+ slug = input.gsub(EXTRACT_LOCAL_EMAIL_PART, "")
+ slug = slug.gsub(FORBIDDEN_CHARACTERS, "")
+
+ # Remove trailing violations ('.atom', '.git', or '.')
+ loop do
+ orig = slug
+ PATH_TRAILING_VIOLATIONS.each { |extension| slug = slug.chomp extension }
+ break if orig == slug
+ end
+ slug = slug.sub(LEADING_DASHES, "")
+
+ # If all characters were of forbidden nature and filtered out we use this
+ # fallback to avoid empty paths
+ slug = DEFAULT_SLUG if slug.blank?
+
+ slug
+ end
+
+ alias_method :to_s, :generate
+
+ private
+
+ attr_reader :input
+ end
+ end
+end
diff --git a/lib/gitlab/utils/email.rb b/lib/gitlab/utils/email.rb
new file mode 100644
index 00000000000..c65d7165263
--- /dev/null
+++ b/lib/gitlab/utils/email.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Utils
+ module Email
+ extend self
+
+ # Replaces most visible characters with * to obfuscate an email address
+ # deform adds a fix number of * to ensure the address cannot be guessed. Also obfuscates TLD with **
+ def obfuscated_email(email, deform: false)
+ regex = ::Gitlab::UntrustedRegexp.new('^(..?)(.*)(@.?)(.*)(\..+)$')
+ match = regex.match(email)
+ return email unless match
+
+ if deform
+ # Ensure we can show two characters for the username, even if the username has
+ # only one character. Boring solution is to just duplicate the character.
+ email_start = match[1]
+ email_start += email_start if email_start.length == 1
+
+ email_start + '*' * 5 + match[3] + '*' * 5 + "#{match[5][0..1]}**"
+ else
+ match[1] + '*' * (match[2] || '').length + match[3] + '*' * (match[4] || '').length + match[5]
+ end
+ end
+ end
+ end
+end
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
index 07444fbd850..6ab42c5877a 100755
--- a/scripts/review_apps/automated_cleanup.rb
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -14,6 +14,7 @@ module ReviewApps
review_app: 'review/',
docs_review_app: 'review-docs/'
}.freeze
+ HELM_ALLOWED_NAMESPACES_REGEX = /^review-(?!apps).+/.freeze
IGNORED_HELM_ERRORS = [
'transport is closing',
'error upgrading connection',
@@ -64,19 +65,21 @@ module ReviewApps
@kubernetes ||= Tooling::KubernetesClient.new(namespace: review_apps_namespace)
end
- def perform_gitlab_environment_cleanup!(days_for_stop:, days_for_delete:)
- puts "Checking for Review Apps not updated in the last #{days_for_stop} days..."
+ def perform_gitlab_environment_cleanup!(days_for_delete:)
+ puts "Checking for Review Apps not updated in the last #{days_for_delete} days..."
checked_environments = []
delete_threshold = threshold_time(days: days_for_delete)
- stop_threshold = threshold_time(days: days_for_stop)
deployments_look_back_threshold = threshold_time(days: days_for_delete * 5)
releases_to_delete = []
# Delete environments via deployments
gitlab.deployments(project_path, per_page: DEPLOYMENTS_PER_PAGE, sort: 'desc').auto_paginate do |deployment|
- break if Time.parse(deployment.created_at) < deployments_look_back_threshold
+ last_deploy = deployment.created_at
+ deployed_at = Time.parse(last_deploy)
+
+ break if deployed_at < deployments_look_back_threshold
environment = deployment.environment
@@ -84,20 +87,13 @@ module ReviewApps
next unless environment.name.start_with?(ENVIRONMENT_PREFIX[:review_app])
next if checked_environments.include?(environment.slug)
- last_deploy = deployment.created_at
- deployed_at = Time.parse(last_deploy)
-
if deployed_at < delete_threshold
deleted_environment = delete_environment(environment, deployment)
+
if deleted_environment
release = Tooling::Helm3Client::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, environment.slug)
releases_to_delete << release
end
- elsif deployed_at >= stop_threshold
- print_release_state(subject: 'Review App', release_name: environment.slug, release_date: last_deploy, action: 'leaving')
- else
- environment_state = fetch_environment(environment)&.state
- stop_environment(environment, deployment) if environment_state && environment_state != 'stopped'
end
checked_environments << environment.slug
@@ -116,18 +112,21 @@ module ReviewApps
checked_environments = []
stop_threshold = threshold_time(days: days_for_stop)
delete_threshold = threshold_time(days: days_for_delete)
+ deployments_look_back_threshold = threshold_time(days: days_for_delete * 5)
# Delete environments via deployments
gitlab.deployments(project_path, per_page: DEPLOYMENTS_PER_PAGE, sort: 'desc').auto_paginate do |deployment|
+ last_deploy = deployment.created_at
+ deployed_at = Time.parse(last_deploy)
+
+ break if deployed_at < deployments_look_back_threshold
+
environment = deployment.environment
next unless environment
next unless environment.name.start_with?(ENVIRONMENT_PREFIX[:docs_review_app])
next if checked_environments.include?(environment.slug)
- last_deploy = deployment.created_at
- deployed_at = Time.parse(last_deploy)
-
if deployed_at < stop_threshold
environment_state = fetch_environment(environment)&.state
stop_environment(environment, deployment) if environment_state && environment_state != 'stopped'
@@ -150,6 +149,7 @@ module ReviewApps
helm_releases.each do |release|
# Prevents deleting `dns-gitlab-review-app` releases or other unrelated releases
+ next unless HELM_ALLOWED_NAMESPACES_REGEX.match?(release.namespace)
next unless release.name.start_with?('review-')
if release.status == 'failed' || release.last_update < threshold
@@ -228,7 +228,7 @@ module ReviewApps
end
def helm_releases
- args = ['--all', '--date']
+ args = ['--all', '--all-namespaces', '--date']
helm.releases(args: args)
end
@@ -304,10 +304,20 @@ if $PROGRAM_NAME == __FILE__
automated_cleanup.perform_helm_releases_cleanup!(days: 2)
end
+ puts
+
+ timed('Review Apps cleanup') do
+ automated_cleanup.perform_gitlab_environment_cleanup!(days_for_delete: 3)
+ end
+
+ puts
+
timed('Stale Namespace cleanup') do
automated_cleanup.perform_stale_namespace_cleanup!(days: 3)
end
+ puts
+
timed('Stale PVC cleanup') do
automated_cleanup.perform_stale_pvc_cleanup!(days: 30)
end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index 0297bb5b935..237f361bd72 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -18,7 +18,6 @@ RSpec.describe 'Merge request > User sees merge widget', :js, feature_category:
end
before do
- stub_feature_flags(refactor_security_extension: false)
project.add_maintainer(user)
project_only_mwps.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/projects/issues/email_participants_spec.rb b/spec/features/projects/issues/email_participants_spec.rb
index 4dedbff608e..fdfd926b763 100644
--- a/spec/features/projects/issues/email_participants_spec.rb
+++ b/spec/features/projects/issues/email_participants_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'viewing an issue', :js, feature_category: :issue_email_participants do
let_it_be(:user) { create(:user) }
+ let_it_be(:non_member) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be_with_refind(:issue) { create(:issue, project: project) }
let_it_be(:note) { create(:note_on_issue, project: project, noteable: issue) }
@@ -19,19 +20,7 @@ RSpec.describe 'viewing an issue', :js, feature_category: :issue_email_participa
end
end
- shared_examples 'no email participants warning' do |selector|
- it 'does not show email participants warning' do
- expect(find(selector)).not_to have_content(", and 1 more will be notified of your comment")
- end
- end
-
- context 'when issue is confidential' do
- before do
- issue.update!(confidential: true)
- sign_in(user)
- visit project_issue_path(project, issue)
- end
-
+ shared_examples 'email participants warning in all editors' do
context 'for a new note' do
it_behaves_like 'email participants warning', '.new-note'
end
@@ -45,22 +34,35 @@ RSpec.describe 'viewing an issue', :js, feature_category: :issue_email_participa
end
end
- context 'when issue is not confidential' do
+ context 'when issue is confidential' do
before do
+ issue.update!(confidential: true)
sign_in(user)
visit project_issue_path(project, issue)
end
- context 'for a new note' do
- it_behaves_like 'no email participants warning', '.new-note'
- end
+ it_behaves_like 'email participants warning in all editors'
+ end
- context 'for a reply form' do
- before do
- find('.js-reply-button').click
+ context 'when issue is not confidential' do
+ context 'with signed in user' do
+ context 'when user has no role in project' do
+ before do
+ sign_in(non_member)
+ visit project_issue_path(project, issue)
+ end
+
+ it_behaves_like 'email participants warning in all editors'
end
- it_behaves_like 'no email participants warning', '.note-edit-form'
+ context 'when user has (at least) reporter role in project' do
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ end
+
+ it_behaves_like 'email participants warning in all editors'
+ end
end
end
end
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index 13dde57d885..0a4075be02f 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -46,10 +46,10 @@ RSpec.describe 'User views releases', :js, feature_category: :continuous_deliver
external_link_indicator_selector = '[data-testid="external-link-indicator"]'
expect(page).to have_link internal_link.name, href: internal_link.url
- expect(find_link(internal_link.name)).not_to have_css(external_link_indicator_selector)
+ expect(find_link(internal_link.name)).to have_css(external_link_indicator_selector)
expect(page).to have_link internal_link_with_redirect.name, href: Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{internal_link_with_redirect.filepath}"
- expect(find_link(internal_link_with_redirect.name)).not_to have_css(external_link_indicator_selector)
+ expect(find_link(internal_link_with_redirect.name)).to have_css(external_link_indicator_selector)
expect(page).to have_link external_link.name, href: external_link.url
expect(find_link(external_link.name)).to have_css(external_link_indicator_selector)
diff --git a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
index 3383a5c86ec..ec20088c443 100644
--- a/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
+++ b/spec/frontend/abuse_reports/components/abuse_category_selector_spec.js
@@ -106,7 +106,7 @@ describe('AbuseCategorySelector', () => {
expect(findUserId().attributes()).toMatchObject({
type: 'hidden',
name: 'user_id',
- value: `${USER_ID}`,
+ value: USER_ID.toString(),
});
});
diff --git a/spec/frontend/ci/runner/components/runner_jobs_table_spec.js b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
index 8defe568df8..281aa1aeb77 100644
--- a/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
+++ b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
@@ -72,7 +72,7 @@ describe('RunnerJobsTable', () => {
});
it('Displays details of a job', () => {
- const { id, detailedStatus, pipeline, shortSha, commitPath } = mockJobs[0];
+ const { id, detailedStatus, project, shortSha, commitPath } = mockJobs[0];
expect(findCell({ field: 'status' }).text()).toMatchInterpolatedText(detailedStatus.text);
@@ -81,10 +81,8 @@ describe('RunnerJobsTable', () => {
detailedStatus.detailsPath,
);
- expect(findCell({ field: 'project' }).text()).toBe(pipeline.project.name);
- expect(findCell({ field: 'project' }).find('a').attributes('href')).toBe(
- pipeline.project.webUrl,
- );
+ expect(findCell({ field: 'project' }).text()).toBe(project.name);
+ expect(findCell({ field: 'project' }).find('a').attributes('href')).toBe(project.webUrl);
expect(findCell({ field: 'commit' }).text()).toBe(shortSha);
expect(findCell({ field: 'commit' }).find('a').attributes('href')).toBe(commitPath);
diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js
index ba0527e5395..acff5d9ed43 100644
--- a/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js
+++ b/spec/frontend/issues/show/components/incidents/timeline_events_item_spec.js
@@ -27,7 +27,7 @@ describe('IncidentTimelineEventList', () => {
const findCommentIcon = () => wrapper.findComponent(GlIcon);
const findEventTime = () => wrapper.findByTestId('event-time');
- const findEventTag = () => wrapper.findComponent(GlBadge);
+ const findEventTags = () => wrapper.findAllComponents(GlBadge);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDeleteButton = () => wrapper.findByText(timelineItemI18n.delete);
@@ -69,15 +69,16 @@ describe('IncidentTimelineEventList', () => {
});
});
- describe('timeline event tag', () => {
- it('does not show when tag is not provided', () => {
- expect(findEventTag().exists()).toBe(false);
- });
-
- it('shows when tag is provided', () => {
- mountComponent({ propsData: { eventTag: 'Start time' } });
+ describe.each([
+ { eventTags: [], expected: 0 },
+ { eventTags: ['Start time'], expected: 1 },
+ { eventTags: ['Start time', 'End time'], expected: 2 },
+ ])('timeline event tags', ({ eventTags, expected }) => {
+ it(`shows ${expected} badges when ${expected} tags are provided`, () => {
+ mountComponent({ propsData: { eventTags } });
- expect(findEventTag().exists()).toBe(true);
+ expect(findEventTags().exists()).toBe(Boolean(expected));
+ expect(findEventTags().length).toBe(eventTags.length);
});
});
diff --git a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
index 8a353668153..26fda877089 100644
--- a/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
+++ b/spec/frontend/issues/show/components/incidents/timeline_events_list_spec.js
@@ -93,9 +93,7 @@ describe('IncidentTimelineEventList', () => {
expect(findItems().at(1).props('occurredAt')).toBe(mockEvents[1].occurredAt);
expect(findItems().at(1).props('action')).toBe(mockEvents[1].action);
expect(findItems().at(1).props('noteHtml')).toBe(mockEvents[1].noteHtml);
- expect(findItems().at(1).props('eventTag')).toBe(
- mockEvents[1].timelineEventTags.nodes[0].name,
- );
+ expect(findItems().at(1).props('eventTags')).toBe(mockEvents[1].timelineEventTags.nodes);
});
it('formats dates correctly', () => {
@@ -124,20 +122,6 @@ describe('IncidentTimelineEventList', () => {
});
});
- describe('getFirstTag', () => {
- it('returns undefined, when timelineEventTags contains an empty array', () => {
- const returnedTag = wrapper.vm.getFirstTag(mockEvents[0].timelineEventTags);
-
- expect(returnedTag).toEqual(undefined);
- });
-
- it('returns the first string, when timelineEventTags contains array with at least one tag', () => {
- const returnedTag = wrapper.vm.getFirstTag(mockEvents[1].timelineEventTags);
-
- expect(returnedTag).toBe(mockEvents[1].timelineEventTags.nodes[0].name);
- });
- });
-
describe('delete functionality', () => {
beforeEach(() => {
mockConfirmAction({ confirmed: true });
diff --git a/spec/frontend/notes/components/note_actions_spec.js b/spec/frontend/notes/components/note_actions_spec.js
index d95e357f24c..1c336a68acf 100644
--- a/spec/frontend/notes/components/note_actions_spec.js
+++ b/spec/frontend/notes/components/note_actions_spec.js
@@ -413,15 +413,15 @@ describe('noteActions', () => {
});
it('opens the drawer when report abuse button is clicked', async () => {
- findReportAbuseButton().trigger('click');
-
- await nextTick();
+ await findReportAbuseButton().trigger('click');
expect(findAbuseCategorySelector().props('showDrawer')).toEqual(true);
});
it('closes the drawer', async () => {
- await findAbuseCategorySelector().vm.$emit('close-drawer');
+ findAbuseCategorySelector().vm.$emit('close-drawer');
+
+ await nextTick();
expect(findAbuseCategorySelector().props('showDrawer')).toEqual(false);
});
diff --git a/spec/frontend/projects/commit/mock_data.js b/spec/frontend/projects/commit/mock_data.js
index 34e9c400af4..e398d46e69c 100644
--- a/spec/frontend/projects/commit/mock_data.js
+++ b/spec/frontend/projects/commit/mock_data.js
@@ -24,5 +24,9 @@ export default {
openModal: '_open_modal_',
},
mockBranches: ['_branch_1', '_abc_', '_main_'],
- mockProjects: ['_project_1', '_abc_', '_project_'],
+ mockProjects: [
+ { id: 1, name: '_project_1', refsUrl: '/_project_1/refs' },
+ { id: 2, name: '_abc_', refsUrl: '/_abc_/refs' },
+ { id: 3, name: '_project_', refsUrl: '/_project_/refs' },
+ ],
};
diff --git a/spec/frontend/projects/commit/store/getters_spec.js b/spec/frontend/projects/commit/store/getters_spec.js
index 38c45af7aa0..f45f3114550 100644
--- a/spec/frontend/projects/commit/store/getters_spec.js
+++ b/spec/frontend/projects/commit/store/getters_spec.js
@@ -29,9 +29,15 @@ describe('Commit form modal getters', () => {
});
it('should provide a uniq list of projects', () => {
- const projects = ['_project_', '_project_', '_some_other_project'];
+ const projects = [
+ { id: 1, name: '_project_', refsUrl: '/_project_/refs' },
+ { id: 1, name: '_project_', refsUrl: '/_project_/refs' },
+ { id: 3, name: '_some_other_project', refsUrl: '/_some_other_project/refs' },
+ ];
const state = { projects };
+ expect(state.projects.length).toBe(3);
+ expect(getters.sortedProjects(state).length).toBe(2);
expect(getters.sortedProjects(state)).toEqual(projects.slice(1));
});
});
diff --git a/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js b/spec/frontend/projects/report_abuse/components/report_abuse_dropdown_item_spec.js
index 11f770fb05e..de0c889e8c9 100644
--- a/spec/frontend/projects/merge_requests/components/report_abuse_dropdown_item_spec.js
+++ b/spec/frontend/projects/report_abuse/components/report_abuse_dropdown_item_spec.js
@@ -3,7 +3,7 @@ import { GlDropdownItem } from '@gitlab/ui';
import { MountingPortal } from 'portal-vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import ReportAbuseDropdownItem from '~/projects/merge_requests/components/report_abuse_dropdown_item.vue';
+import ReportAbuseDropdownItem from '~/projects/report_abuse/components/report_abuse_dropdown_item.vue';
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
describe('ReportAbuseDropdownItem', () => {
diff --git a/spec/frontend/releases/components/release_block_assets_spec.js b/spec/frontend/releases/components/release_block_assets_spec.js
index 4f94e4dfd55..6d53bf5a49e 100644
--- a/spec/frontend/releases/components/release_block_assets_spec.js
+++ b/spec/frontend/releases/components/release_block_assets_spec.js
@@ -123,42 +123,14 @@ describe('Release block assets', () => {
});
});
- describe('external vs internal links', () => {
+ describe('links', () => {
const containsExternalSourceIndicator = () =>
wrapper.find('[data-testid="external-link-indicator"]').exists();
- describe('when a link is external', () => {
- beforeEach(() => {
- defaultProps.assets.sources = [];
- defaultProps.assets.links = [
- {
- ...defaultProps.assets.links[0],
- external: true,
- },
- ];
- createComponent(defaultProps);
- });
-
- it('renders the link with an "external source" indicator', () => {
- expect(containsExternalSourceIndicator()).toBe(true);
- });
- });
+ beforeEach(() => createComponent(defaultProps));
- describe('when a link is internal', () => {
- beforeEach(() => {
- defaultProps.assets.sources = [];
- defaultProps.assets.links = [
- {
- ...defaultProps.assets.links[0],
- external: false,
- },
- ];
- createComponent(defaultProps);
- });
-
- it('renders the link without the "external source" indicator', () => {
- expect(containsExternalSourceIndicator()).toBe(false);
- });
+ it('renders with an external source indicator (except for sections with no title)', () => {
+ expect(containsExternalSourceIndicator()).toBe(true);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports_spec.js b/spec/frontend/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports_spec.js
index 16c2adaffaf..e23cd92f53e 100644
--- a/spec/frontend/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports_spec.js
@@ -82,11 +82,8 @@ describe('vue_merge_request_widget/extensions/security_reports/mr_widget_securit
createComponent({ mockResponse: { data: { project: { id: 'project-id' } } } });
});
- it('displays the correct message', () => {
- expect(wrapper.findByText('Security scans have run').exists()).toBe(true);
- });
-
- it('should not display the artifacts dropdown', () => {
+ it('does not render the widget', () => {
+ expect(wrapper.html()).toBe('');
expect(findDropdown().exists()).toBe(false);
});
});
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 467c8d96cfb..5470476c45a 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -200,6 +200,41 @@ RSpec.describe IssuablesHelper, feature_category: :team_planning do
expect(content).not_to match('gl-emoji')
end
end
+
+ describe 'service desk reply to email address' do
+ let(:email) { 'user@example.com' }
+ let(:obfuscated_email) { 'us*****@e*****.c**' }
+ let(:service_desk_issue) { build_stubbed(:issue, project: project, author: User.support_bot, service_desk_reply_to: email) }
+
+ subject { helper.issuable_meta(service_desk_issue, project) }
+
+ context 'with anonymous user' do
+ before do
+ allow(helper).to receive(:current_user).and_return(nil)
+ end
+
+ it { is_expected.to have_content(obfuscated_email) }
+ end
+
+ context 'with signed in user' do
+ context 'when user has no role in project' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ it { is_expected.to have_content(obfuscated_email) }
+ end
+
+ context 'when user has reporter role in project' do
+ before do
+ project.add_reporter(user)
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ it { is_expected.to have_content(email) }
+ end
+ end
+ end
end
describe '#issuables_state_counter_text' do
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
index 06005a447a8..53a0e718eb6 100644
--- a/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
@@ -108,10 +108,10 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImpor
it 'schedule import for each merge request reviewers' do
expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
- .to receive(:perform_in).with(1.minute, *expected_worker_payload.first).ordered
+ .to receive(:perform_in).with(1.minute, *expected_worker_payload.first)
expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
- .to receive(:perform_in).with(1.minute, *expected_worker_payload.second).ordered
+ .to receive(:perform_in).with(1.minute, *expected_worker_payload.second)
importer.parallel_import
end
diff --git a/spec/lib/gitlab/slug/path_spec.rb b/spec/lib/gitlab/slug/path_spec.rb
new file mode 100644
index 00000000000..9a7067e40a2
--- /dev/null
+++ b/spec/lib/gitlab/slug/path_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Slug::Path, feature_category: :not_owned do
+ describe '#generate' do
+ {
+ 'name': 'name',
+ 'james.atom@bond.com': 'james',
+ '--foobar--': 'foobar--',
+ '--foo_bar--': 'foo_bar--',
+ '--foo$^&_bar--': 'foo_bar--',
+ 'john@doe.com': 'john',
+ '-john+gitlab-ETC%.git@gmail.com': 'johngitlab-ETC',
+ 'this.is.git.atom.': 'this.is',
+ '#$%^.': 'blank',
+ '---.git#$.atom%@atom^.': 'blank', # use default when all characters are filtered out
+ '--gitlab--hey.git#$.atom%@atom^.': 'gitlab--hey'
+ }.each do |input, output|
+ it "yields a slug #{output} when given #{input}" do
+ slug = described_class.new(input).generate
+
+ expect(slug).to match(/\A#{output}\z/)
+ end
+ end
+ end
+
+ describe '#to_s' do
+ it 'presents with a cleaned slug' do
+ expect(described_class.new('---show-me-what-you.got.git').to_s).to match(/\Ashow-me-what-you.got\z/)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/utils/email_spec.rb b/spec/lib/gitlab/utils/email_spec.rb
new file mode 100644
index 00000000000..d7a881d8655
--- /dev/null
+++ b/spec/lib/gitlab/utils/email_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+RSpec.describe Gitlab::Utils::Email, feature_category: :service_desk do
+ using RSpec::Parameterized::TableSyntax
+
+ describe '.obfuscated_email' do
+ where(:input, :output) do
+ 'alex@gitlab.com' | 'al**@g*****.com'
+ 'alex@gl.co.uk' | 'al**@g****.uk'
+ 'a@b.c' | 'a@b.c'
+ 'q@example.com' | 'q@e******.com'
+ 'q@w.' | 'q@w.'
+ 'a@b' | 'a@b'
+ 'no mail' | 'no mail'
+ end
+
+ with_them do
+ it { expect(described_class.obfuscated_email(input)).to eq(output) }
+ end
+
+ context 'when deform is active' do
+ where(:input, :output) do
+ 'alex@gitlab.com' | 'al*****@g*****.c**'
+ 'alex@gl.co.uk' | 'al*****@g*****.u**'
+ 'a@b.c' | 'aa*****@b*****.c**'
+ 'qqwweerrttyy@example.com' | 'qq*****@e*****.c**'
+ 'getsuperfancysupport@paywhatyouwant.accounting' | 'ge*****@p*****.a**'
+ 'q@example.com' | 'qq*****@e*****.c**'
+ 'q@w.' | 'q@w.'
+ 'a@b' | 'a@b'
+ 'no mail' | 'no mail'
+ end
+
+ with_them do
+ it { expect(described_class.obfuscated_email(input, deform: true)).to eq(output) }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index c44bb64a5c0..a554e0b26a8 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -81,10 +81,6 @@ RSpec.describe Gitlab do
describe '.com?' do
context 'when not simulating SaaS' do
- before do
- stub_env('GITLAB_SIMULATE_SAAS', '0')
- end
-
it "is true when on #{Gitlab::Saas.com_url}" do
stub_config_setting(url: Gitlab::Saas.com_url)
@@ -118,17 +114,31 @@ RSpec.describe Gitlab do
end
end
- it 'is true when GITLAB_SIMULATE_SAAS is true and in development' do
- stub_rails_env('development')
- stub_env('GITLAB_SIMULATE_SAAS', '1')
+ context 'when simulating SaaS' do
+ before do
+ stub_const('Gitlab::GITLAB_SIMULATE_SAAS', '1')
+ end
- expect(described_class.com?).to eq true
- end
+ it 'is false in tests' do
+ expect(described_class.com?).to eq false
+ end
+
+ it 'is true in development' do
+ stub_rails_env('development')
- it 'is false when GITLAB_SIMULATE_SAAS is true and in test' do
- stub_env('GITLAB_SIMULATE_SAAS', '1')
+ expect(described_class.com?).to eq true
+ end
- expect(described_class.com?).to eq false
+ # See ee/spec/lib/gitlab_spec.rb for EE-specific changes to this behavior.
+ context 'in a production environment' do
+ before do
+ stub_rails_env('production')
+ end
+
+ it 'is false' do
+ expect(described_class.com?).to eq false
+ end
+ end
end
end
@@ -236,54 +246,6 @@ RSpec.describe Gitlab do
end
end
- describe '.simulate_com?' do
- subject { described_class.simulate_com? }
-
- context 'when GITLAB_SIMULATE_SAAS is true' do
- before do
- stub_env('GITLAB_SIMULATE_SAAS', '1')
- end
-
- it 'is false when test env' do
- expect(subject).to eq false
- end
-
- it 'is true when dev env' do
- stub_rails_env('development')
-
- expect(subject).to eq true
- end
-
- it 'is false when env is not dev' do
- stub_rails_env('production')
-
- expect(subject).to eq false
- end
- end
-
- context 'when GITLAB_SIMULATE_SAAS is false' do
- before do
- stub_env('GITLAB_SIMULATE_SAAS', '0')
- end
-
- it 'is false when test env' do
- expect(subject).to eq false
- end
-
- it 'is false when dev env' do
- stub_rails_env('development')
-
- expect(subject).to eq false
- end
-
- it 'is false when env is not dev or test' do
- stub_rails_env('production')
-
- expect(subject).to eq false
- end
- end
- end
-
describe '.dev_or_test_env?' do
subject { described_class.dev_or_test_env? }
diff --git a/spec/lib/service_ping/build_payload_spec.rb b/spec/lib/service_ping/build_payload_spec.rb
index b10c9fd5bc0..6c37168f5a0 100644
--- a/spec/lib/service_ping/build_payload_spec.rb
+++ b/spec/lib/service_ping/build_payload_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ServicePing::BuildPayload do
+RSpec.describe ServicePing::BuildPayload, feature_category: :service_ping do
describe '#execute', :without_license do
subject(:service_ping_payload) { described_class.new.execute }
diff --git a/spec/models/ci_platform_metric_spec.rb b/spec/models/ci_platform_metric_spec.rb
index f73db713791..e59730792b8 100644
--- a/spec/models/ci_platform_metric_spec.rb
+++ b/spec/models/ci_platform_metric_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe CiPlatformMetric do
+RSpec.describe CiPlatformMetric, feature_category: :continuous_integration do
subject { build(:ci_platform_metric) }
it_behaves_like 'a BulkInsertSafe model', CiPlatformMetric do
diff --git a/spec/models/concerns/bulk_insert_safe_spec.rb b/spec/models/concerns/bulk_insert_safe_spec.rb
index 577004c2cf6..65b7da20bbc 100644
--- a/spec/models/concerns/bulk_insert_safe_spec.rb
+++ b/spec/models/concerns/bulk_insert_safe_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BulkInsertSafe do
+RSpec.describe BulkInsertSafe, feature_category: :database do
before(:all) do
ActiveRecord::Schema.define do
create_table :_test_bulk_insert_parent_items, force: true do |t|
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index b0601ea3f08..57e0d1cad8b 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe DesignManagement::Design do
+RSpec.describe DesignManagement::Design, feature_category: :design_management do
include DesignManagementTestHelpers
let_it_be(:issue) { create(:issue) }
diff --git a/spec/models/issue_email_participant_spec.rb b/spec/models/issue_email_participant_spec.rb
index 09c231bbfda..8ddc9a5f478 100644
--- a/spec/models/issue_email_participant_spec.rb
+++ b/spec/models/issue_email_participant_spec.rb
@@ -7,6 +7,12 @@ RSpec.describe IssueEmailParticipant do
it { is_expected.to belong_to(:issue) }
end
+ describe 'Modules' do
+ subject { described_class }
+
+ it { is_expected.to include_module(Presentable) }
+ end
+
describe 'Validations' do
subject { build(:issue_email_participant) }
diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb
index 25e5e40feb7..78f9fb5b7d3 100644
--- a/spec/models/merge_request_diff_commit_spec.rb
+++ b/spec/models/merge_request_diff_commit_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequestDiffCommit do
+RSpec.describe MergeRequestDiffCommit, feature_category: :code_review_workflow do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
index 7e127caa649..eee7fe67ffb 100644
--- a/spec/models/merge_request_diff_file_spec.rb
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe MergeRequestDiffFile do
+RSpec.describe MergeRequestDiffFile, feature_category: :code_review_workflow do
it_behaves_like 'a BulkInsertSafe model', MergeRequestDiffFile do
let(:valid_items_for_bulk_insertion) do
build_list(:merge_request_diff_file, 10) do |mr_diff_file|
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 63b8ebcecab..852df3b8a90 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -1265,12 +1265,23 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
describe ".clean_path" do
- let!(:user) { create(:user, username: "johngitlab-etc") }
- let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") }
+ it "cleans the path and makes sure it's available", time_travel_to: '2023-04-20 00:07 -0700' do
+ create :user, username: "johngitlab-etc"
+ create :namespace, path: "JohnGitLab-etc1"
+ [nil, 1, 2, 3].each do |count|
+ create :namespace, path: "pickle#{count}"
+ end
- it "cleans the path and makes sure it's available" do
expect(described_class.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
expect(described_class.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name")
+
+ # when we have more than MAX_TRIES count of a path use a more randomized suffix
+ expect(described_class.clean_path("pickle@gmail.com")).to eq("pickle4")
+ create(:namespace, path: "pickle4")
+ expect(described_class.clean_path("pickle@gmail.com")).to eq("pickle716")
+ create(:namespace, path: "pickle716")
+ expect(described_class.clean_path("pickle@gmail.com")).to eq("pickle717")
+ expect(described_class.clean_path("--$--pickle@gmail.com")).to eq("pickle717")
end
end
diff --git a/spec/models/namespaces/randomized_suffix_path_spec.rb b/spec/models/namespaces/randomized_suffix_path_spec.rb
new file mode 100644
index 00000000000..a2484030f3c
--- /dev/null
+++ b/spec/models/namespaces/randomized_suffix_path_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Namespaces::RandomizedSuffixPath, feature_category: :not_owned do
+ let(:path) { 'backintime' }
+
+ subject(:suffixed_path) { described_class.new(path) }
+
+ describe '#to_s' do
+ it 'represents with given path' do
+ expect(suffixed_path.to_s).to eq('backintime')
+ end
+ end
+
+ describe '#call' do
+ it 'returns path without count when count is 0' do
+ expect(suffixed_path.call(0)).to eq('backintime')
+ end
+
+ it "returns path suffixed with count when between 0 and #{described_class::MAX_TRIES}" do
+ (1..described_class::MAX_TRIES).each do |count|
+ expect(suffixed_path.call(count)).to eq("backintime#{count}")
+ end
+ end
+
+ it 'adds a "randomized" suffix when MAX_TRIES is exhausted', time_travel_to: '1955-11-12 06:38' do
+ count = described_class::MAX_TRIES + 1
+ expect(suffixed_path.call(count)).to eq("backintime3845")
+ end
+
+ it 'adds an offset to the "randomized" suffix when MAX_TRIES is exhausted', time_travel_to: '1955-11-12 06:38' do
+ count = described_class::MAX_TRIES + 2
+ expect(suffixed_path.call(count)).to eq("backintime3846")
+ end
+ end
+end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b7dcf9919c7..3485c877373 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -566,16 +566,6 @@ RSpec.describe Repository, feature_category: :source_code_management do
expect(commit_ids).to include(*expected_commit_ids)
expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
end
-
- context 'when feature flag "commit_search_trailing_spaces" is disabled' do
- before do
- stub_feature_flags(commit_search_trailing_spaces: false)
- end
-
- it 'returns an empty list' do
- expect(commit_ids).to be_empty
- end
- end
end
describe 'when storage is broken', :broken_storage do
diff --git a/spec/presenters/issue_email_participant_presenter_spec.rb b/spec/presenters/issue_email_participant_presenter_spec.rb
new file mode 100644
index 00000000000..c270fae3058
--- /dev/null
+++ b/spec/presenters/issue_email_participant_presenter_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssueEmailParticipantPresenter, feature_category: :service_desk do
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/389247
+ # for details around build_stubbed for access level
+ let_it_be(:non_member) { create(:user) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:guest) { create(:user) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:reporter) { create(:user) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:developer) { create(:user) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:group) { create(:group) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:project) { create(:project, group: group) } # rubocop:todo RSpec/FactoryBot/AvoidCreate
+ let_it_be(:issue) { build_stubbed(:issue, project: project) }
+ let_it_be(:participant) { build_stubbed(:issue_email_participant, issue: issue, email: 'any@email.com') }
+
+ let(:user) { nil }
+ let(:presenter) { described_class.new(participant, current_user: user) }
+ let(:obfuscated_email) { 'an*****@e*****.c**' }
+ let(:email) { 'any@email.com' }
+
+ before_all do
+ group.add_guest(guest)
+ group.add_reporter(reporter)
+ group.add_developer(developer)
+ end
+
+ describe '#email' do
+ subject { presenter.email }
+
+ it { is_expected.to eq(obfuscated_email) }
+
+ context 'with signed in user' do
+ context 'when user has no role in project' do
+ let(:user) { non_member }
+
+ it { is_expected.to eq(obfuscated_email) }
+ end
+
+ context 'when user has guest role in project' do
+ let(:user) { guest }
+
+ it { is_expected.to eq(obfuscated_email) }
+ end
+
+ context 'when user has reporter role in project' do
+ let(:user) { reporter }
+
+ it { is_expected.to eq(email) }
+ end
+
+ context 'when user has developer role in project' do
+ let(:user) { developer }
+
+ it { is_expected.to eq(email) }
+ end
+ end
+ end
+end
diff --git a/spec/presenters/issue_presenter_spec.rb b/spec/presenters/issue_presenter_spec.rb
index df43b0279dd..22a86d04a5a 100644
--- a/spec/presenters/issue_presenter_spec.rb
+++ b/spec/presenters/issue_presenter_spec.rb
@@ -6,16 +6,25 @@ RSpec.describe IssuePresenter do
include Gitlab::Routing.url_helpers
let_it_be(:user) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:developer) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:task) { create(:issue, :task, project: project) }
+ let_it_be(:non_member) { create(:user) }
let(:presented_issue) { issue }
let(:presenter) { described_class.new(presented_issue, current_user: user) }
+ let(:obfuscated_email) { 'an*****@e*****.c**' }
+ let(:email) { 'any@email.com' }
before_all do
group.add_developer(user)
+ group.add_developer(developer)
+ group.add_reporter(reporter)
+ group.add_guest(guest)
end
describe '#web_url' do
@@ -99,4 +108,69 @@ RSpec.describe IssuePresenter do
it { is_expected.to be(true) }
end
end
+
+ describe '#service_desk_reply_to' do
+ context 'when issue is not a service desk issue' do
+ subject { presenter.service_desk_reply_to }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when issue is a service desk issue' do
+ let(:service_desk_issue) do
+ create(:issue, project: project, author: User.support_bot, service_desk_reply_to: email)
+ end
+
+ let(:user) { nil }
+
+ subject { described_class.new(service_desk_issue, current_user: user).service_desk_reply_to }
+
+ it { is_expected.to eq obfuscated_email }
+
+ context 'with signed in user' do
+ context 'when user has no role in project' do
+ let(:user) { non_member }
+
+ it { is_expected.to eq obfuscated_email }
+ end
+
+ context 'when user has guest role in project' do
+ let(:user) { guest }
+
+ it { is_expected.to eq obfuscated_email }
+ end
+
+ context 'when user has reporter role in project' do
+ let(:user) { reporter }
+
+ it { is_expected.to eq email }
+ end
+
+ context 'when user has developer role in project' do
+ let(:user) { developer }
+
+ it { is_expected.to eq email }
+ end
+ end
+ end
+ end
+
+ describe '#issue_email_participants' do
+ let(:participants_issue) { create(:issue, project: project) }
+
+ subject { described_class.new(participants_issue, current_user: user).issue_email_participants }
+
+ it { is_expected.to be_empty }
+
+ context "when an issue email participant exists" do
+ before do
+ participants_issue.issue_email_participants.create!(email: email)
+ end
+
+ it "has one element that is a presenter" do
+ expect(subject.size).to eq(1)
+ expect(subject.first).to be_a(IssueEmailParticipantPresenter)
+ end
+ end
+ end
end
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index 9d53d8bb235..4bb1e00fa18 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -164,21 +164,57 @@ RSpec.describe IssueEntity do
it_behaves_like 'issuable entity current_user properties'
context 'when issue has email participants' do
+ let(:obfuscated_email) { 'an*****@e*****.c**' }
+ let(:email) { 'any@email.com' }
+
before do
- resource.issue_email_participants.create!(email: 'any@email.com')
+ resource.issue_email_participants.create!(email: email)
end
- context 'when issue is confidential' do
- it 'returns email participants' do
- resource.update!(confidential: true)
+ context 'with anonymous user' do
+ it 'returns obfuscated email participants email' do
+ request = double('request', current_user: nil)
- expect(subject[:issue_email_participants]).to match_array([{ email: "any@email.com" }])
+ response = described_class.new(resource, request: request).as_json
+ expect(response[:issue_email_participants]).to eq([{ email: obfuscated_email }])
end
end
- context 'when issue is not confidential' do
- it 'returns empty array' do
- expect(subject[:issue_email_participants]).to be_empty
+ context 'with signed in user' do
+ context 'when user has no role in project' do
+ it 'returns obfuscated email participants email' do
+ expect(subject[:issue_email_participants]).to eq([{ email: obfuscated_email }])
+ end
+ end
+
+ context 'when user has guest role in project' do
+ let(:member) { create(:user) }
+
+ before do
+ project.add_guest(member)
+ end
+
+ it 'returns obfuscated email participants email' do
+ request = double('request', current_user: member)
+
+ response = described_class.new(resource, request: request).as_json
+ expect(response[:issue_email_participants]).to eq([{ email: obfuscated_email }])
+ end
+ end
+
+ context 'when user has (at least) reporter role in project' do
+ let(:member) { create(:user) }
+
+ before do
+ project.add_reporter(member)
+ end
+
+ it 'returns full email participants email' do
+ request = double('request', current_user: member)
+
+ response = described_class.new(resource, request: request).as_json
+ expect(response[:issue_email_participants]).to eq([{ email: email }])
+ end
end
end
end
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 17ef8a85c2b..8c90946e09e 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Notes::CreateService do
+RSpec.describe Notes::CreateService, feature_category: :team_planning do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user) }
@@ -438,7 +438,7 @@ RSpec.describe Notes::CreateService do
end
end
- context 'for merge requests' do
+ context 'for merge requests', feature_category: :code_review_workflow do
let_it_be(:merge_request) { create(:merge_request, source_project: project, labels: [bug_label]) }
let(:issuable) { merge_request }
@@ -512,7 +512,7 @@ RSpec.describe Notes::CreateService do
end
end
- context 'personal snippet note' do
+ context 'personal snippet note', feature_category: :snippets do
subject { described_class.new(nil, user, params).execute }
let(:snippet) { create(:personal_snippet) }
@@ -533,7 +533,7 @@ RSpec.describe Notes::CreateService do
end
end
- context 'design note' do
+ context 'design note', feature_category: :design_management do
subject(:service) { described_class.new(project, user, params) }
let_it_be(:design) { create(:design, :with_file) }
diff --git a/spec/services/packages/debian/generate_distribution_service_spec.rb b/spec/services/packages/debian/generate_distribution_service_spec.rb
index 53805d03655..6d179c791a3 100644
--- a/spec/services/packages/debian/generate_distribution_service_spec.rb
+++ b/spec/services/packages/debian/generate_distribution_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Packages::Debian::GenerateDistributionService do
+RSpec.describe Packages::Debian::GenerateDistributionService, feature_category: :package_registry do
describe '#execute' do
subject { described_class.new(distribution).execute }
diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
index 6e2caa853f8..616f8f2345c 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -38,7 +38,7 @@ RSpec.shared_context 'ProjectPolicy context' do
read_commit_status read_confidential_issues read_container_image
read_harbor_registry read_deployment read_environment read_merge_request
read_metrics_dashboard_annotation read_pipeline read_prometheus
- read_sentry_issue update_issue create_merge_request_in
+ read_sentry_issue update_issue create_merge_request_in read_external_emails
]
end
diff --git a/spec/support/shared_examples/features/reportable_note_shared_examples.rb b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
index e9056edbafa..bb3fab5b23e 100644
--- a/spec/support/shared_examples/features/reportable_note_shared_examples.rb
+++ b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
@@ -20,9 +20,10 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
+ expect(dropdown).to have_button('Report abuse to administrator')
+
if type == 'issue' || type == 'merge_request'
expect(dropdown).to have_button('Delete comment')
- expect(dropdown).to have_button('Report abuse to administrator')
else
expect(dropdown).to have_link('Delete comment', href: note_url(note, project))
end
@@ -32,21 +33,14 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
- if type == 'issue' || type == 'merge_request'
- dropdown.click_button('Report abuse to administrator')
+ dropdown.click_button('Report abuse to administrator')
- choose "They're posting spam."
- click_button "Next"
+ choose "They're posting spam."
+ click_button "Next"
- expect(find('#user_name')['value']).to match(note.author.username)
- expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
- expect(find('#abuse_report_category', visible: false)['value']).to match('spam')
- else
- dropdown.click_link('Report abuse to administrator')
-
- expect(find('#user_name')['value']).to match(note.author.username)
- expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
- end
+ expect(find('#user_name')['value']).to match(note.author.username)
+ expect(find('#abuse_report_reported_from_url')['value']).to match(noteable_note_url(note))
+ expect(find('#abuse_report_category', visible: false)['value']).to match('spam')
end
def open_dropdown(dropdown)
diff --git a/spec/support/shared_examples/integrations/integration_settings_form.rb b/spec/support/shared_examples/integrations/integration_settings_form.rb
index 5eeefdf7e50..1074bcc420c 100644
--- a/spec/support/shared_examples/integrations/integration_settings_form.rb
+++ b/spec/support/shared_examples/integrations/integration_settings_form.rb
@@ -4,7 +4,7 @@ RSpec.shared_examples 'integration settings form' do
include IntegrationsHelper
# Note: these specs don't validate channel fields
# which are present on a few integrations
- it 'displays all the integrations' do
+ it 'displays all the integrations', feature_category: :integrations do
aggregate_failures do
integrations.each do |integration|
stub_feature_flags(integration_slack_app_notifications: false)
diff --git a/spec/support/shared_examples/serializers/note_entity_shared_examples.rb b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
index 2e557ca090c..b5e3a407b53 100644
--- a/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
@@ -38,6 +38,10 @@ RSpec.shared_examples 'note entity' do
expect(subject[:current_user]).to include(:can_edit, :can_award_emoji, :can_resolve, :can_resolve_discussion)
end
+ it 'exposes the report_abuse_path' do
+ expect(subject[:report_abuse_path]).to eq(add_category_abuse_reports_path)
+ end
+
describe ':can_resolve_discussion' do
context 'discussion is resolvable' do
before do
diff --git a/spec/views/projects/issues/_issue.html.haml_spec.rb b/spec/views/projects/issues/_issue.html.haml_spec.rb
index 29bef557304..e4485f253b6 100644
--- a/spec/views/projects/issues/_issue.html.haml_spec.rb
+++ b/spec/views/projects/issues/_issue.html.haml_spec.rb
@@ -37,6 +37,59 @@ RSpec.describe 'projects/issues/_issue.html.haml' do
end
end
+ context 'when issue is service desk issue' do
+ let_it_be(:email) { 'user@example.com' }
+ let_it_be(:obfuscated_email) { 'us*****@e*****.c**' }
+ let_it_be(:issue) { create(:issue, author: User.support_bot, service_desk_reply_to: email) }
+
+ context 'with anonymous user' do
+ it 'obfuscates service_desk_reply_to email for anonymous user' do
+ expect(rendered).to have_content(obfuscated_email)
+ end
+ end
+
+ context 'with signed in user' do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:issue).and_return(issue)
+ end
+
+ context 'when user has no role in project' do
+ it 'obfuscates service_desk_reply_to email' do
+ render
+
+ expect(rendered).to have_content(obfuscated_email)
+ end
+ end
+
+ context 'when user has guest role in project' do
+ before do
+ issue.project.add_guest(user)
+ end
+
+ it 'obfuscates service_desk_reply_to email' do
+ render
+
+ expect(rendered).to have_content(obfuscated_email)
+ end
+ end
+
+ context 'when user has (at least) reporter role in project' do
+ before do
+ issue.project.add_reporter(user)
+ end
+
+ it 'shows full service_desk_reply_to email' do
+ render
+
+ expect(rendered).to have_content(email)
+ end
+ end
+ end
+ end
+
def format_timestamp(time)
l(time, format: "%b %d, %Y")
end
diff --git a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
index 7886a811c9a..d604eb2c8d6 100644
--- a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
+++ b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'projects/notes/_more_actions_dropdown' do
it 'shows Report abuse to admin button if not editable and not current users comment' do
render 'projects/notes/more_actions_dropdown', current_user: not_author_user, note_editable: false, note: note
- expect(rendered).to have_link('Report abuse to administrator')
+ expect(rendered).to have_selector('.js-report-abuse-dropdown-item')
end
it 'does not show the More actions button if not editable and current users comment' do
@@ -29,7 +29,8 @@ RSpec.describe 'projects/notes/_more_actions_dropdown' do
it 'shows Report abuse and Delete buttons if editable and not current users comment' do
render 'projects/notes/more_actions_dropdown', current_user: not_author_user, note_editable: true, note: note
- expect(rendered).to have_link('Report abuse to administrator')
+ expect(rendered).to have_selector('.js-report-abuse-dropdown-item')
+
expect(rendered).to have_link('Delete comment')
end
diff --git a/spec/workers/packages/debian/generate_distribution_worker_spec.rb b/spec/workers/packages/debian/generate_distribution_worker_spec.rb
index a4627ec5d36..390a5e15e66 100644
--- a/spec/workers/packages/debian/generate_distribution_worker_spec.rb
+++ b/spec/workers/packages/debian/generate_distribution_worker_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Packages::Debian::GenerateDistributionWorker, type: :worker do
+RSpec.describe Packages::Debian::GenerateDistributionWorker, type: :worker,
+feature_category: :package_registry do
describe '#perform' do
let(:container_type) { distribution.container_type }
let(:distribution_id) { distribution.id }